@@ -27,19 +27,59 @@ class PresetChild implements JsonSerializable
2727 /**
2828 * Create a new preset child instance.
2929 */
30- public function __construct (string $ type )
30+ public function __construct (? string $ type = null )
3131 {
32- $ this ->type = $ type ;
32+ // Call build() first to allow subclass configuration
33+ $ this ->build ();
34+
35+ // Set type with priority: constructor param > build() set value > getType()
36+ $ this ->type = $ type ?? $ this ->type ?? $ this ->getType ();
3337 }
3438
3539 /**
3640 * Create a new preset child.
3741 */
38- public static function make (string $ type ): static
42+ public static function make (? string $ type = null ): static
3943 {
4044 return new static ($ type );
4145 }
4246
47+ /**
48+ * Get default preset child type.
49+ * Can be overridden in subclasses to provide a custom type.
50+ */
51+ protected function getType (): string
52+ {
53+ $ class = (new \ReflectionClass (static ::class))->getShortName ();
54+
55+ // Remove "PresetChild" or "Child" suffix if present
56+ $ class = preg_replace ('/(PresetChild|Child)$/ ' , '' , $ class );
57+
58+ // Convert PascalCase to kebab-case (e.g., "Paragraph" -> "paragraph")
59+ $ kebab = strtolower (preg_replace ('/(?<!^)[A-Z]/ ' , '-$0 ' , $ class ));
60+
61+ return $ kebab ;
62+ }
63+
64+ /**
65+ * Build the preset child configuration.
66+ * Override this method in subclasses to define structure.
67+ */
68+ protected function build (): void
69+ {
70+ // Base implementation does nothing
71+ }
72+
73+ /**
74+ * Set the block type.
75+ */
76+ public function type (string $ type ): static
77+ {
78+ $ this ->type = $ type ;
79+
80+ return $ this ;
81+ }
82+
4383 /**
4484 * Set the block's semantic ID.
4585 */
@@ -85,7 +125,7 @@ public function static(bool $static = true): static
85125 */
86126 public function blocks (array $ children ): static
87127 {
88- $ this ->children = $ children ;
128+ $ this ->children = static :: normalizeChildren ( $ children) ;
89129
90130 return $ this ;
91131 }
@@ -98,6 +138,78 @@ public function children(array $children): static
98138 return $ this ->blocks ($ children );
99139 }
100140
141+ /**
142+ * Normalize children array by converting class names to instances.
143+ *
144+ * @param array $children Raw children array (may contain class names, instances, or arrays)
145+ * @return array Normalized children array (instances and arrays)
146+ */
147+ protected static function normalizeChildren (array $ children ): array
148+ {
149+ return array_map (function ($ item ) {
150+ // If it's a class string that exists and extends PresetChild
151+ if (is_string ($ item ) && class_exists ($ item )) {
152+ if (is_subclass_of ($ item , self ::class)) {
153+ // Call ::make() to instantiate (type will be auto-derived)
154+ return $ item ::make ();
155+ }
156+ }
157+
158+ // Otherwise return as-is (PresetChild instance or array)
159+ return $ item ;
160+ }, $ children );
161+ }
162+
163+ /**
164+ * Append a single child block to this preset child.
165+ */
166+ public function addChild (self |array |string $ child ): static
167+ {
168+ $ normalized = static ::normalizeChildren ([$ child ]);
169+ $ this ->children [] = $ normalized [0 ];
170+
171+ return $ this ;
172+ }
173+
174+ /**
175+ * Append multiple child blocks to this preset child.
176+ */
177+ public function addChildren (array $ children ): static
178+ {
179+ $ normalized = static ::normalizeChildren ($ children );
180+ foreach ($ normalized as $ child ) {
181+ $ this ->children [] = $ child ;
182+ }
183+
184+ return $ this ;
185+ }
186+
187+ /**
188+ * Append a single child block (alias for addChild()).
189+ */
190+ public function addBlock (self |array |string $ child ): static
191+ {
192+ return $ this ->addChild ($ child );
193+ }
194+
195+ /**
196+ * Append multiple child blocks (alias for addChildren()).
197+ */
198+ public function addBlocks (array $ children ): static
199+ {
200+ return $ this ->addChildren ($ children );
201+ }
202+
203+ /**
204+ * Merge additional properties into existing properties.
205+ */
206+ public function mergeProperties (array $ properties ): static
207+ {
208+ $ this ->properties = array_merge ($ this ->properties , $ properties );
209+
210+ return $ this ;
211+ }
212+
101213 /**
102214 * Convert to array representation.
103215 */
0 commit comments