Skip to content

Commit cb0d156

Browse files
committed
chore: make sure <object data="string" and data-*> can co-exist
1 parent 0d743d5 commit cb0d156

115 files changed

Lines changed: 1041 additions & 237 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/TemplateGenerator/NextJSGenerator.php

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ public function renderElement(HTMLElementDelegatorInterface $element): string
207207
$level = 'inline'; // Will be determined by class hierarchy
208208

209209
$componentName = ucfirst($elementName);
210+
// Avoid shadowing global Object in TS
211+
if ($componentName === 'Object') {
212+
$componentName = 'ObjectComponent';
213+
}
210214

211215
$props = [];
212216
$propsInterface = [];
@@ -498,15 +502,27 @@ private function buildNextJSComponent(
498502
$tsx .= " const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};\n\n";
499503

500504
// Handle data attributes specially
501-
if (isset($props['data'])) {
505+
if (isset($props['dataSet'])) {
502506
$tsx .= " // Handle data attributes specially\n";
503-
$tsx .= " if (data) {\n";
504-
$tsx .= " Object.entries(data).forEach(([key, value]) => {\n";
507+
$tsx .= " if (dataSet) {\n";
508+
$tsx .= " Object.entries(dataSet).forEach(([key, value]: [string, string]) => {\n";
505509
$tsx .= " elementProps[`data-\${key}`] = value;\n";
506510
$tsx .= " });\n";
507511
$tsx .= " }\n\n";
508512
}
509513

514+
// Handle 'data' attribute (string) for <object data="...">
515+
if (isset($props['data']) && !isset($props['dataSet'])) {
516+
$tsx .= " if (data !== undefined) {\n";
517+
$tsx .= " elementProps['data'] = data;\n";
518+
$tsx .= " }\n\n";
519+
}
520+
if (isset($props['data']) && isset($props['dataSet'])) {
521+
$tsx .= " if (data !== undefined) {\n";
522+
$tsx .= " elementProps['data'] = data;\n";
523+
$tsx .= " }\n\n";
524+
}
525+
510526
$tsx .= " // Convert camelCase to kebab-case for attribute names\n";
511527
$tsx .= " const toKebabCase = (str: string): string => {\n";
512528
$tsx .= " return str.replace(/([a-z])([A-Z])/g, '\$1-\$2').toLowerCase();\n";
@@ -516,7 +532,7 @@ private function buildNextJSComponent(
516532
$tsx .= " const excludedProps = new Set(['children', 'data']);\n\n";
517533

518534
$tsx .= " // Iterate over all props and map them to element attributes\n";
519-
$tsx .= " Object.entries(props).forEach(([key, value]) => {\n";
535+
$tsx .= " Object.entries(props).forEach(([key, value]: [string, any]) => {\n";
520536
$tsx .= " if (excludedProps.has(key) || value === undefined) {\n";
521537
$tsx .= " return;\n";
522538
$tsx .= " }\n\n";

templates/nextjs/block/article/article.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Article
66
* @description The article element represents a self-contained composition in a document, page, application, or site, which is intended to be independently distributable or reusable.
77
*/
@@ -87,6 +87,13 @@ export const Article: React.FC<ArticleProps> = (props: ArticleProps) => {
8787

8888
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
8989

90+
// Handle data attributes specially
91+
if (dataSet) {
92+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
93+
elementProps[`data-${key}`] = value;
94+
});
95+
}
96+
9097
// Convert camelCase to kebab-case for attribute names
9198
const toKebabCase = (str: string): string => {
9299
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -96,7 +103,7 @@ export const Article: React.FC<ArticleProps> = (props: ArticleProps) => {
96103
const excludedProps = new Set(['children', 'data']);
97104

98105
// Iterate over all props and map them to element attributes
99-
Object.entries(props).forEach(([key, value]) => {
106+
Object.entries(props).forEach(([key, value]: [string, any]) => {
100107
if (excludedProps.has(key) || value === undefined) {
101108
return;
102109
}

templates/nextjs/block/aside/aside.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Aside
66
* @description The aside element represents a section of a page that consists of content that is tangentially related to the content around the aside element, and which could be considered separate from that content.
77
*/
@@ -89,6 +89,13 @@ export const Aside: React.FC<AsideProps> = (props: AsideProps) => {
8989

9090
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
9191

92+
// Handle data attributes specially
93+
if (dataSet) {
94+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
95+
elementProps[`data-${key}`] = value;
96+
});
97+
}
98+
9299
// Convert camelCase to kebab-case for attribute names
93100
const toKebabCase = (str: string): string => {
94101
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -98,7 +105,7 @@ export const Aside: React.FC<AsideProps> = (props: AsideProps) => {
98105
const excludedProps = new Set(['children', 'data']);
99106

100107
// Iterate over all props and map them to element attributes
101-
Object.entries(props).forEach(([key, value]) => {
108+
Object.entries(props).forEach(([key, value]: [string, any]) => {
102109
if (excludedProps.has(key) || value === undefined) {
103110
return;
104111
}

templates/nextjs/block/audio/audio.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Audio
66
* @description The audio element is used to embed sound content in documents. It may contain one or more audio sources, represented using the src attribute or the source element.
77
*/
@@ -87,6 +87,13 @@ export const Audio: React.FC<AudioProps> = (props: AudioProps) => {
8787

8888
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
8989

90+
// Handle data attributes specially
91+
if (dataSet) {
92+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
93+
elementProps[`data-${key}`] = value;
94+
});
95+
}
96+
9097
// Convert camelCase to kebab-case for attribute names
9198
const toKebabCase = (str: string): string => {
9299
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -96,7 +103,7 @@ export const Audio: React.FC<AudioProps> = (props: AudioProps) => {
96103
const excludedProps = new Set(['children', 'data']);
97104

98105
// Iterate over all props and map them to element attributes
99-
Object.entries(props).forEach(([key, value]) => {
106+
Object.entries(props).forEach(([key, value]: [string, any]) => {
100107
if (excludedProps.has(key) || value === undefined) {
101108
return;
102109
}

templates/nextjs/block/blockquote/blockquote.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Blockquote
66
* @description The blockquote element represents a section that is quoted from another source. Content inside a blockquote must be quoted from another source, whose address, if it has one, may be cited in the cite attribute.
77
*/
@@ -89,6 +89,13 @@ export const Blockquote: React.FC<BlockquoteProps> = (props: BlockquoteProps) =>
8989

9090
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
9191

92+
// Handle data attributes specially
93+
if (dataSet) {
94+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
95+
elementProps[`data-${key}`] = value;
96+
});
97+
}
98+
9299
// Convert camelCase to kebab-case for attribute names
93100
const toKebabCase = (str: string): string => {
94101
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -98,7 +105,7 @@ export const Blockquote: React.FC<BlockquoteProps> = (props: BlockquoteProps) =>
98105
const excludedProps = new Set(['children', 'data']);
99106

100107
// Iterate over all props and map them to element attributes
101-
Object.entries(props).forEach(([key, value]) => {
108+
Object.entries(props).forEach(([key, value]: [string, any]) => {
102109
if (excludedProps.has(key) || value === undefined) {
103110
return;
104111
}

templates/nextjs/block/body/body.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Body
66
* @description The body element represents the content of an HTML document. All the contents such as text, images, headings, links, tables, etc. are placed between the body tags.
77
*/
@@ -81,6 +81,13 @@ export const Body: React.FC<BodyProps> = (props: BodyProps) => {
8181

8282
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
8383

84+
// Handle data attributes specially
85+
if (dataSet) {
86+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
87+
elementProps[`data-${key}`] = value;
88+
});
89+
}
90+
8491
// Convert camelCase to kebab-case for attribute names
8592
const toKebabCase = (str: string): string => {
8693
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -90,7 +97,7 @@ export const Body: React.FC<BodyProps> = (props: BodyProps) => {
9097
const excludedProps = new Set(['children', 'data']);
9198

9299
// Iterate over all props and map them to element attributes
93-
Object.entries(props).forEach(([key, value]) => {
100+
Object.entries(props).forEach(([key, value]: [string, any]) => {
94101
if (excludedProps.has(key) || value === undefined) {
95102
return;
96103
}

templates/nextjs/block/canvas/canvas.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Canvas
66
* @description The canvas element is used to draw graphics, on the fly, via scripting (usually JavaScript).
77
*/
@@ -91,6 +91,13 @@ export const Canvas: React.FC<CanvasProps> = (props: CanvasProps) => {
9191

9292
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
9393

94+
// Handle data attributes specially
95+
if (dataSet) {
96+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
97+
elementProps[`data-${key}`] = value;
98+
});
99+
}
100+
94101
// Convert camelCase to kebab-case for attribute names
95102
const toKebabCase = (str: string): string => {
96103
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -100,7 +107,7 @@ export const Canvas: React.FC<CanvasProps> = (props: CanvasProps) => {
100107
const excludedProps = new Set(['children', 'data']);
101108

102109
// Iterate over all props and map them to element attributes
103-
Object.entries(props).forEach(([key, value]) => {
110+
Object.entries(props).forEach(([key, value]: [string, any]) => {
104111
if (excludedProps.has(key) || value === undefined) {
105112
return;
106113
}

templates/nextjs/block/caption/caption.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Caption
66
* @description The caption element represents the title of the table that is its parent, if it has a parent and that is a table element.
77
*/
@@ -87,6 +87,13 @@ export const Caption: React.FC<CaptionProps> = (props: CaptionProps) => {
8787

8888
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
8989

90+
// Handle data attributes specially
91+
if (dataSet) {
92+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
93+
elementProps[`data-${key}`] = value;
94+
});
95+
}
96+
9097
// Convert camelCase to kebab-case for attribute names
9198
const toKebabCase = (str: string): string => {
9299
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -96,7 +103,7 @@ export const Caption: React.FC<CaptionProps> = (props: CaptionProps) => {
96103
const excludedProps = new Set(['children', 'data']);
97104

98105
// Iterate over all props and map them to element attributes
99-
Object.entries(props).forEach(([key, value]) => {
106+
Object.entries(props).forEach(([key, value]: [string, any]) => {
100107
if (excludedProps.has(key) || value === undefined) {
101108
return;
102109
}

templates/nextjs/block/colgroup/colgroup.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Colgroup
66
* @description The colgroup element represents a group of one or more columns in the table that is its parent, if it has a parent and that is a table element.
77
*/
@@ -43,6 +43,13 @@ export const Colgroup: React.FC<ColgroupProps> = (props: ColgroupProps) => {
4343

4444
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
4545

46+
// Handle data attributes specially
47+
if (dataSet) {
48+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
49+
elementProps[`data-${key}`] = value;
50+
});
51+
}
52+
4653
// Convert camelCase to kebab-case for attribute names
4754
const toKebabCase = (str: string): string => {
4855
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -52,7 +59,7 @@ export const Colgroup: React.FC<ColgroupProps> = (props: ColgroupProps) => {
5259
const excludedProps = new Set(['children', 'data']);
5360

5461
// Iterate over all props and map them to element attributes
55-
Object.entries(props).forEach(([key, value]) => {
62+
Object.entries(props).forEach(([key, value]: [string, any]) => {
5663
if (excludedProps.has(key) || value === undefined) {
5764
return;
5865
}

templates/nextjs/block/datalist/datalist.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* THIS FILE IS AUTOGENERATED. DO NOT EDIT IT.
33
*
4-
* @generated December 12, 2025 08:41:45
4+
* @generated December 12, 2025 08:50:55
55
* @component Datalist
66
* @description The datalist element contains a set of option elements that represent the permissible or recommended options available to users.
77
*/
@@ -87,6 +87,13 @@ export const Datalist: React.FC<DatalistProps> = (props: DatalistProps) => {
8787

8888
const elementProps: React.HTMLAttributes<HTMLElement> & Record<string, any> = {};
8989

90+
// Handle data attributes specially
91+
if (dataSet) {
92+
Object.entries(dataSet).forEach(([key, value]: [string, string]) => {
93+
elementProps[`data-${key}`] = value;
94+
});
95+
}
96+
9097
// Convert camelCase to kebab-case for attribute names
9198
const toKebabCase = (str: string): string => {
9299
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
@@ -96,7 +103,7 @@ export const Datalist: React.FC<DatalistProps> = (props: DatalistProps) => {
96103
const excludedProps = new Set(['children', 'data']);
97104

98105
// Iterate over all props and map them to element attributes
99-
Object.entries(props).forEach(([key, value]) => {
106+
Object.entries(props).forEach(([key, value]: [string, any]) => {
100107
if (excludedProps.has(key) || value === undefined) {
101108
return;
102109
}

0 commit comments

Comments
 (0)