@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,111 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from "@wordpress/i18n";
5
+
6
+ /**
7
+ * External dependencies
8
+ */
9
+ import styled from "@emotion/styled";
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { CaptchaContainer, InvisibleNotice } from "./styles";
15
+
16
+ const Turnstile = styled.div`
17
+ display: inline-flex;
18
+ align-items: center;
19
+ background: ${props => {
20
+ if (props.theme === 'dark') { return '#1f1f1f'; }
21
+ if (props.mode === 'non-interactive') { return '#f9fafb'; }
22
+ return 'white';
23
+ }};
24
+ border: 1px solid ${props => props.theme === 'dark' ? '#444' : '#ddd'};
25
+ color: ${props => props.theme === 'dark' ? '#fff' : 'inherit'};
26
+ border-radius: 8px;
27
+ padding: 12px 16px;
28
+ box-shadow: 0 2px 8px rgba(0,0,0,0.08);
29
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
30
+ position: relative;
31
+ min-width: 300px;
32
+ cursor: not-allowed;
33
+
34
+ ${props => props.theme === 'auto' && `
35
+ @media (prefers-color-scheme: dark) {
36
+ background: #1f1f1f;
37
+ border-color: #444;
38
+ color: #fff;
39
+ }
40
+ `}
41
+ `;
42
+
43
+ const TurnstileCheckbox = styled.div`
44
+ width: 24px;
45
+ height: 24px;
46
+ border: 2px solid #d1d5db;
47
+ border-radius: 4px;
48
+ margin-right: 12px;
49
+ background: white;
50
+ `;
51
+
52
+ const TurnstileLabel = styled.div`
53
+ flex: 1;
54
+ font-size: 14px;
55
+ color: ${props => props.theme === 'dark' ? '#fff' : '#374151'};
56
+ `;
57
+
58
+ const TurnstileSpinner = styled.div`
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 12px;
62
+ `;
63
+
64
+ const TurnstileSpinnerInner = styled.div`
65
+ width: 24px;
66
+ height: 24px;
67
+ border: 3px solid #e5e7eb;
68
+ border-top-color: #f97316;
69
+ border-radius: 50%;
70
+ animation: spin 1s linear infinite;
71
+
72
+ @keyframes spin {
73
+ to { transform: rotate(360deg); }
74
+ }
75
+ `;
76
+
77
+ const TurnstileLogo = styled.div`
78
+ font-size: 12px;
79
+ color: #f97316;
80
+ font-weight: 600;
81
+ `;
82
+
83
+ export function CloudflareTurnstile({ theme, mode }) {
84
+ if (mode === 'invisible') {
85
+ return (
86
+ <InvisibleNotice>
87
+ {__("Invisible captcha - runs automatically on form submission", "wp-component-library")}
88
+ </InvisibleNotice>
89
+ );
90
+ }
91
+
92
+ return (
93
+ <CaptchaContainer>
94
+ <Turnstile theme={theme} mode={mode}>
95
+ {mode === 'managed' && (
96
+ <>
97
+ <TurnstileCheckbox />
98
+ <TurnstileLabel theme={theme}>{__("Verify you are human", "wp-component-library")}</TurnstileLabel>
99
+ </>
100
+ )}
101
+ {mode === 'non-interactive' && (
102
+ <TurnstileSpinner>
103
+ <TurnstileSpinnerInner />
104
+ <TurnstileLabel theme={theme}>{__("Verifying…", "wp-component-library")}</TurnstileLabel>
105
+ </TurnstileSpinner>
106
+ )}
107
+ <TurnstileLogo>Cloudflare</TurnstileLogo>
108
+ </Turnstile>
109
+ </CaptchaContainer>
110
+ );
111
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from "@wordpress/i18n";
5
+
6
+ /**
7
+ * External dependencies
8
+ */
9
+ import styled from "@emotion/styled";
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { CaptchaContainer, CheckboxBorder, RECAPTCHA_LOGO_BASE64 } from "./styles";
15
+
16
+ const RecaptchaV2 = styled.div`
17
+ display: inline-flex;
18
+ align-items: center;
19
+ background: ${props => props.theme === 'dark' ? '#222' : '#f9f9f9'};
20
+ border: 1px solid ${props => props.theme === 'dark' ? '#555' : '#d3d3d3'};
21
+ color: ${props => props.theme === 'dark' ? '#e8eaed' : 'inherit'};
22
+ border-radius: 3px;
23
+ padding: ${props => props.size === 'compact' ? '6px 8px' : '10px 12px'};
24
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
25
+ font-family: Roboto, Arial, sans-serif;
26
+ position: relative;
27
+ cursor: not-allowed;
28
+ font-size: ${props => props.size === 'compact' ? '12px' : '14px'};
29
+ `;
30
+
31
+ const RecaptchaLabel = styled.div`
32
+ margin-right: 12px;
33
+ font-size: 14px;
34
+ color: #555;
35
+ `;
36
+
37
+ const RecaptchaLogo = styled.div`
38
+ margin-left: auto;
39
+ display: flex;
40
+ align-items: center;
41
+ gap: 8px;
42
+
43
+ img {
44
+ width: 32px;
45
+ height: 32px;
46
+ }
47
+ `;
48
+
49
+ const RecaptchaText = styled.div`
50
+ display: flex;
51
+ flex-direction: column;
52
+ font-size: 10px;
53
+ color: #555;
54
+ line-height: 1.2;
55
+
56
+ span {
57
+ font-weight: 500;
58
+ }
59
+
60
+ small {
61
+ color: #1a73e8;
62
+ }
63
+ `;
64
+
65
+ const RecaptchaV3Badge = styled.div`
66
+ display: inline-flex;
67
+ align-items: center;
68
+ background: white;
69
+ border: 1px solid #ddd;
70
+ border-radius: 3px;
71
+ padding: 8px 12px;
72
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
73
+ font-size: 9px;
74
+ color: #555;
75
+ `;
76
+
77
+ const RecaptchaV3Logo = styled.div`
78
+ margin-right: 8px;
79
+
80
+ img {
81
+ width: 24px;
82
+ height: 24px;
83
+ }
84
+ `;
85
+
86
+ const RecaptchaV3Text = styled.div`
87
+ line-height: 1.2;
88
+
89
+ strong {
90
+ font-size: 10px;
91
+ }
92
+ `;
93
+
94
+ const RecaptchaV3Links = styled.div`
95
+ color: #1a73e8;
96
+ margin-top: 2px;
97
+ `;
98
+
99
+ export function GoogleRecaptchaV2({ theme, size }) {
100
+ return (
101
+ <CaptchaContainer>
102
+ <RecaptchaV2 theme={theme} size={size}>
103
+ <CheckboxBorder />
104
+ <RecaptchaLabel>{__("I'm not a robot", "wp-component-library")}</RecaptchaLabel>
105
+ <RecaptchaLogo>
106
+ <img src={RECAPTCHA_LOGO_BASE64} alt="reCAPTCHA" />
107
+ <RecaptchaText>
108
+ <span>reCAPTCHA</span>
109
+ <small>Privacy - Terms</small>
110
+ </RecaptchaText>
111
+ </RecaptchaLogo>
112
+ </RecaptchaV2>
113
+ </CaptchaContainer>
114
+ );
115
+ }
116
+
117
+ export function GoogleRecaptchaV3() {
118
+ return (
119
+ <CaptchaContainer>
120
+ <RecaptchaV3Badge>
121
+ <RecaptchaV3Logo>
122
+ <img src={RECAPTCHA_LOGO_BASE64} alt="reCAPTCHA" />
123
+ </RecaptchaV3Logo>
124
+ <RecaptchaV3Text>
125
+ protected by<br/>
126
+ <strong>reCAPTCHA</strong>
127
+ <RecaptchaV3Links>Privacy - Terms</RecaptchaV3Links>
128
+ </RecaptchaV3Text>
129
+ </RecaptchaV3Badge>
130
+ </CaptchaContainer>
131
+ );
132
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from "@wordpress/i18n";
5
+
6
+ /**
7
+ * External dependencies
8
+ */
9
+ import styled from "@emotion/styled";
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import { CaptchaContainer } from "./styles";
15
+
16
+ const HCaptchaWrapper = styled.div`
17
+ display: inline-flex;
18
+ align-items: center;
19
+ background: ${props => props.theme === 'dark' ? '#333' : '#fafafa'};
20
+ border: 1px solid ${props => props.theme === 'dark' ? '#555' : '#e0e0e0'};
21
+ color: ${props => props.theme === 'dark' ? '#fff' : 'inherit'};
22
+ border-radius: 4px;
23
+ padding: ${props => props.size === 'compact' ? '8px 10px' : '12px 14px'};
24
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
25
+ position: relative;
26
+ cursor: not-allowed;
27
+ font-size: ${props => props.size === 'compact' ? '13px' : '15px'};
28
+ `;
29
+
30
+ const HCaptchaCheckbox = styled.div`
31
+ width: 28px;
32
+ height: 28px;
33
+ border: 2px solid #0074bf;
34
+ border-radius: 4px;
35
+ margin-right: 12px;
36
+ background: white;
37
+ position: relative;
38
+ `;
39
+
40
+ const HCaptchaLabel = styled.div`
41
+ margin-right: 12px;
42
+ font-size: 15px;
43
+ color: ${props => props.theme === 'dark' ? '#fff' : '#333'};
44
+ `;
45
+
46
+ const HCaptchaLogo = styled.div`
47
+ margin-left: auto;
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 8px;
51
+ `;
52
+
53
+ const HCaptchaLogoSvg = styled.div`
54
+ width: 24px;
55
+ height: 24px;
56
+ background: #0074bf;
57
+ color: white;
58
+ border-radius: 4px;
59
+ display: flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ font-weight: bold;
63
+ font-size: 16px;
64
+ `;
65
+
66
+ const HCaptchaText = styled.div`
67
+ display: flex;
68
+ flex-direction: column;
69
+ font-size: 10px;
70
+ color: #666;
71
+ line-height: 1.2;
72
+
73
+ span {
74
+ font-weight: 500;
75
+ color: ${props => props.theme === 'dark' ? '#fff' : '#333'};
76
+ }
77
+
78
+ small {
79
+ color: #0074bf;
80
+ }
81
+ `;
82
+
83
+ export function HCaptcha({ theme, size }) {
84
+ return (
85
+ <CaptchaContainer>
86
+ <HCaptchaWrapper theme={theme} size={size}>
87
+ <HCaptchaCheckbox />
88
+ <HCaptchaLabel theme={theme}>{__("I am human", "wp-component-library")}</HCaptchaLabel>
89
+ <HCaptchaLogo>
90
+ <HCaptchaLogoSvg>h</HCaptchaLogoSvg>
91
+ <HCaptchaText theme={theme}>
92
+ <span>hCaptcha</span>
93
+ <small>Privacy - Terms</small>
94
+ </HCaptchaText>
95
+ </HCaptchaLogo>
96
+ </HCaptchaWrapper>
97
+ </CaptchaContainer>
98
+ );
99
+ }
@@ -0,0 +1,228 @@
1
+ # CaptchaPlaceholder Component
2
+
3
+ A unified captcha component that provides a consistent interface for rendering different captcha providers. Supports Google reCAPTCHA (v2 & v3), hCaptcha, and Cloudflare Turnstile with customizable themes and sizes.
4
+
5
+ ## Features
6
+
7
+ - Multiple captcha provider support
8
+ - Unified API across all providers
9
+ - Theme customization (light, dark, auto)
10
+ - Size variants (normal, compact)
11
+ - Provider-specific configuration options
12
+ - Clean abstraction with modular architecture
13
+
14
+ ## Supported Providers
15
+
16
+ - **Google reCAPTCHA v2** - Traditional checkbox captcha
17
+ - **Google reCAPTCHA v3** - Invisible behavioral analysis
18
+ - **hCaptcha** - Privacy-focused reCAPTCHA alternative
19
+ - **Cloudflare Turnstile** - Modern captcha solution from Cloudflare
20
+
21
+ ## Usage
22
+
23
+ ```jsx
24
+ import { CaptchaPlaceholder } from '@siratik/wp-component-library/components/captcha-placeholder';
25
+
26
+ // Google reCAPTCHA v2
27
+ <CaptchaPlaceholder
28
+ provider="google-recaptcha"
29
+ version="v2"
30
+ theme="light"
31
+ size="normal"
32
+ />
33
+
34
+ // Google reCAPTCHA v3 (invisible)
35
+ <CaptchaPlaceholder
36
+ provider="google-recaptcha"
37
+ version="v3"
38
+ />
39
+
40
+ // hCaptcha
41
+ <CaptchaPlaceholder
42
+ provider="hcaptcha"
43
+ theme="dark"
44
+ size="compact"
45
+ />
46
+
47
+ // Cloudflare Turnstile
48
+ <CaptchaPlaceholder
49
+ provider="cloudflare-turnstile"
50
+ theme="auto"
51
+ mode="managed"
52
+ />
53
+ ```
54
+
55
+ ## Props
56
+
57
+ | Prop | Type | Default | Description |
58
+ |------|------|---------|-------------|
59
+ | `provider` | `string` | Required | Captcha provider: "google-recaptcha", "hcaptcha", or "cloudflare-turnstile" |
60
+ | `theme` | `string` | `"light"` | Visual theme: "light", "dark", or "auto" |
61
+ | `size` | `string` | `"normal"` | Captcha size: "normal" or "compact" |
62
+ | `version` | `string` | `"v2"` | Google reCAPTCHA version: "v2" or "v3" (Google only) |
63
+ | `mode` | `string` | `"managed"` | Cloudflare Turnstile mode: "managed", "non-interactive", or "invisible" |
64
+
65
+ ## Provider-Specific Configuration
66
+
67
+ ### Google reCAPTCHA
68
+
69
+ #### Version 2 (Checkbox)
70
+ ```jsx
71
+ <CaptchaPlaceholder
72
+ provider="google-recaptcha"
73
+ version="v2"
74
+ theme="light" // or "dark"
75
+ size="normal" // or "compact"
76
+ />
77
+ ```
78
+
79
+ #### Version 3 (Invisible)
80
+ ```jsx
81
+ <CaptchaPlaceholder
82
+ provider="google-recaptcha"
83
+ version="v3"
84
+ // v3 is invisible, theme and size are ignored
85
+ />
86
+ ```
87
+
88
+ ### hCaptcha
89
+ ```jsx
90
+ <CaptchaPlaceholder
91
+ provider="hcaptcha"
92
+ theme="dark" // "light", "dark", or "auto"
93
+ size="compact" // "normal" or "compact"
94
+ />
95
+ ```
96
+
97
+ ### Cloudflare Turnstile
98
+ ```jsx
99
+ <CaptchaPlaceholder
100
+ provider="cloudflare-turnstile"
101
+ theme="auto" // "light", "dark", or "auto"
102
+ mode="managed" // "managed", "non-interactive", or "invisible"
103
+ />
104
+ ```
105
+
106
+ ## Theme Options
107
+
108
+ - **light** - Light background, dark text
109
+ - **dark** - Dark background, light text
110
+ - **auto** - Automatically matches user's system preference (Turnstile & hCaptcha only)
111
+
112
+ ## Size Options
113
+
114
+ - **normal** - Standard size captcha
115
+ - **compact** - Smaller footprint for space-constrained layouts
116
+
117
+ ## Cloudflare Turnstile Modes
118
+
119
+ - **managed** - Cloudflare decides when to show challenges
120
+ - **non-interactive** - Never shows interactive challenges
121
+ - **invisible** - Completely hidden from view
122
+
123
+ ## Examples
124
+
125
+ ### Form with reCAPTCHA v2
126
+ ```jsx
127
+ function ContactForm() {
128
+ return (
129
+ <form>
130
+ <input type="email" placeholder="Email" />
131
+ <textarea placeholder="Message" />
132
+
133
+ <CaptchaPlaceholder
134
+ provider="google-recaptcha"
135
+ version="v2"
136
+ theme="light"
137
+ />
138
+
139
+ <button type="submit">Send</button>
140
+ </form>
141
+ );
142
+ }
143
+ ```
144
+
145
+ ### Dark Mode Support
146
+ ```jsx
147
+ function DarkModeForm({ isDarkMode }) {
148
+ return (
149
+ <form>
150
+ <CaptchaPlaceholder
151
+ provider="hcaptcha"
152
+ theme={isDarkMode ? "dark" : "light"}
153
+ size="normal"
154
+ />
155
+ </form>
156
+ );
157
+ }
158
+ ```
159
+
160
+ ### Invisible Protection
161
+ ```jsx
162
+ function SecureAction() {
163
+ return (
164
+ <div>
165
+ <button onClick={handleAction}>
166
+ Perform Secure Action
167
+ </button>
168
+
169
+ <CaptchaPlaceholder
170
+ provider="cloudflare-turnstile"
171
+ mode="invisible"
172
+ />
173
+ </div>
174
+ );
175
+ }
176
+ ```
177
+
178
+ ### Compact Layout
179
+ ```jsx
180
+ function SidebarForm() {
181
+ return (
182
+ <aside className="sidebar">
183
+ <form>
184
+ <input type="text" />
185
+
186
+ <CaptchaPlaceholder
187
+ provider="hcaptcha"
188
+ size="compact"
189
+ theme="auto"
190
+ />
191
+
192
+ <button>Submit</button>
193
+ </form>
194
+ </aside>
195
+ );
196
+ }
197
+ ```
198
+
199
+ ## Integration Notes
200
+
201
+ ### Site Keys Required
202
+ Each provider requires site keys to be configured:
203
+ - Google reCAPTCHA: Obtain from [Google reCAPTCHA Admin](https://www.google.com/recaptcha/admin)
204
+ - hCaptcha: Get from [hCaptcha Dashboard](https://dashboard.hcaptcha.com)
205
+ - Cloudflare Turnstile: Available in [Cloudflare Dashboard](https://dash.cloudflare.com)
206
+
207
+ ### Server-Side Validation
208
+ Remember to validate captcha responses on your server:
209
+ 1. Capture the captcha response token
210
+ 2. Send to your server with form data
211
+ 3. Verify with the provider's API
212
+ 4. Process form only if verification succeeds
213
+
214
+ ### Styling
215
+ The component renders provider-specific markup. Additional styling can be applied via wrapper elements:
216
+ ```jsx
217
+ <div className="captcha-wrapper">
218
+ <CaptchaPlaceholder {...props} />
219
+ </div>
220
+ ```
221
+
222
+ ## Notes
223
+
224
+ - Returns `null` for unsupported providers
225
+ - Each provider component is loaded separately for optimal bundle size
226
+ - Theme and size support varies by provider
227
+ - Ensure you comply with each provider's terms of service
228
+ - Consider privacy implications when choosing a provider
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { GoogleRecaptchaV2, GoogleRecaptchaV3 } from './GoogleRecaptcha';
5
+ import { HCaptcha } from './HCaptcha';
6
+ import { CloudflareTurnstile } from './CloudflareTurnstile';
7
+
8
+ /**
9
+ * Captcha placeholder component
10
+ *
11
+ * @param {Object} props Component props
12
+ * @param {string} props.provider - The captcha provider (google-recaptcha, hcaptcha, cloudflare-turnstile)
13
+ * @param {string} props.theme - Theme for the captcha (light, dark, auto)
14
+ * @param {string} props.size - Size for the captcha (normal, compact)
15
+ * @param {string} props.version - Version for Google reCAPTCHA (v2, v3)
16
+ * @param {string} props.mode - Mode for Cloudflare Turnstile (managed, non-interactive, invisible)
17
+ * @returns {WPElement} Captcha placeholder element
18
+ */
19
+ export function CaptchaPlaceholder({ provider, theme = 'light', size = 'normal', version = 'v2', mode = 'managed' }) {
20
+ if (provider === 'google-recaptcha' && version === 'v2') {
21
+ return <GoogleRecaptchaV2 theme={theme} size={size} />;
22
+ }
23
+
24
+ if (provider === 'google-recaptcha' && version === 'v3') {
25
+ return <GoogleRecaptchaV3 />;
26
+ }
27
+
28
+ if (provider === 'hcaptcha') {
29
+ return <HCaptcha theme={theme} size={size} />;
30
+ }
31
+
32
+ if (provider === 'cloudflare-turnstile') {
33
+ return <CloudflareTurnstile theme={theme} mode={mode} />;
34
+ }
35
+
36
+ return null;
37
+ }
38
+
39
+ export default CaptchaPlaceholder;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import styled from "@emotion/styled";
5
+
6
+ export const CaptchaContainer = styled.div`
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: flex-start;
10
+ margin-bottom: 16px;
11
+ `;
12
+
13
+ export const CheckboxBorder = styled.div`
14
+ width: 24px;
15
+ height: 24px;
16
+ border: 2px solid #c1c1c1;
17
+ border-radius: 2px;
18
+ margin-right: 12px;
19
+ background: white;
20
+ position: relative;
21
+ `;
22
+
23
+ export const InvisibleNotice = styled.div`
24
+ padding: 12px 16px;
25
+ background: #f0f9ff;
26
+ border: 1px solid #bae6fd;
27
+ border-radius: 4px;
28
+ color: #0369a1;
29
+ font-size: 13px;
30
+ text-align: center;
31
+ `;
32
+
33
+ export const RECAPTCHA_LOGO_BASE64 = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyIDJDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6bS0yIDE1bC01LTUgMS40MS0xLjQxTDEwIDE0LjE3bDcuNTktNy41OUwxOSA4bC05IDl6IiBmaWxsPSIjNDI4NUY0Ii8+Cjwvc3ZnPg==";