@delmaredigital/payload-puck 0.6.26 → 0.6.28

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.
@@ -153,6 +153,23 @@
153
153
  }
154
154
  }
155
155
  },
156
+ Columns: {
157
+ ai: {
158
+ instructions: 'Use when content must be targeted into specific columns (each column is its own drop zone), e.g. a text column beside an image column. For content that just flows across equal cells, prefer Grid.'
159
+ },
160
+ fields: {
161
+ count: {
162
+ ai: {
163
+ instructions: 'Number of columns, 2-4.'
164
+ }
165
+ },
166
+ distribution: {
167
+ ai: {
168
+ instructions: "Column width split. 'equal' for even columns, or an fr ratio like '2:1' / '1:2' / '1:1:2' for asymmetric layouts (must match the column count)."
169
+ }
170
+ }
171
+ }
172
+ },
156
173
  // Content Components
157
174
  Card: {
158
175
  ai: {
@@ -25,6 +25,7 @@
25
25
  export { ContainerConfig } from './layout/Container.js';
26
26
  export { FlexConfig } from './layout/Flex.js';
27
27
  export { GridConfig } from './layout/Grid.js';
28
+ export { ColumnsConfig } from './layout/Columns.js';
28
29
  export { SectionConfig } from './layout/Section.js';
29
30
  export { SpacerConfig } from './layout/Spacer.js';
30
31
  export { TemplateConfig } from './layout/Template.js';
@@ -40,6 +41,7 @@ export { AccordionConfig } from './interactive/Accordion.js';
40
41
  export { ContainerConfig as ContainerServerConfig } from './layout/Container.server.js';
41
42
  export { FlexConfig as FlexServerConfig } from './layout/Flex.server.js';
42
43
  export { GridConfig as GridServerConfig } from './layout/Grid.server.js';
44
+ export { ColumnsConfig as ColumnsServerConfig } from './layout/Columns.server.js';
43
45
  export { SectionConfig as SectionServerConfig } from './layout/Section.server.js';
44
46
  export { SpacerConfig as SpacerServerConfig } from './layout/Spacer.server.js';
45
47
  export { TemplateServerConfig } from './layout/Template.server.js';
@@ -29,6 +29,7 @@
29
29
  export { ContainerConfig } from './layout/Container.js';
30
30
  export { FlexConfig } from './layout/Flex.js';
31
31
  export { GridConfig } from './layout/Grid.js';
32
+ export { ColumnsConfig } from './layout/Columns.js';
32
33
  export { SectionConfig } from './layout/Section.js';
33
34
  export { SpacerConfig } from './layout/Spacer.js';
34
35
  export { TemplateConfig } from './layout/Template.js';
@@ -53,6 +54,7 @@ export { AccordionConfig } from './interactive/Accordion.js';
53
54
  export { ContainerConfig as ContainerServerConfig } from './layout/Container.server.js';
54
55
  export { FlexConfig as FlexServerConfig } from './layout/Flex.server.js';
55
56
  export { GridConfig as GridServerConfig } from './layout/Grid.server.js';
57
+ export { ColumnsConfig as ColumnsServerConfig } from './layout/Columns.server.js';
56
58
  export { SectionConfig as SectionServerConfig } from './layout/Section.server.js';
57
59
  export { SpacerConfig as SpacerServerConfig } from './layout/Spacer.server.js';
58
60
  export { TemplateServerConfig } from './layout/Template.server.js';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Columns Component - Puck Configuration (editor)
3
+ *
4
+ * Unlike Grid (a single CSS-grid slot where children auto-place into cells),
5
+ * Columns exposes one independent drop zone PER column — components can be
6
+ * dropped into a specific column. Puck slots are static named fields, so a fixed
7
+ * maximum set of column slots (column1..columnN) is declared and only the first
8
+ * `count` are rendered.
9
+ *
10
+ * Responsive: stacks vertically on mobile, switches to a CSS grid at md+ (≥768px).
11
+ *
12
+ * Width distribution supports equal columns or fr ratios (e.g. 2:1, 1:2, 1:1:2)
13
+ * for asymmetric layouts.
14
+ */
15
+ import type { ComponentConfig } from '@puckeditor/core';
16
+ import { type PaddingValue, type BorderValue, type DimensionsValue, type BackgroundValue, type AnimationValue, type ResponsiveValue, type VisibilityValue } from '../../fields/shared.js';
17
+ export declare const MAX_COLUMNS = 4;
18
+ export type ColumnCount = 2 | 3 | 4;
19
+ export interface ColumnsProps {
20
+ column1: unknown;
21
+ column2: unknown;
22
+ column3: unknown;
23
+ column4: unknown;
24
+ count: ColumnCount;
25
+ distribution: string;
26
+ gap: number;
27
+ background: BackgroundValue | null;
28
+ customPadding: ResponsiveValue<PaddingValue> | PaddingValue | null;
29
+ dimensions: ResponsiveValue<DimensionsValue> | DimensionsValue | null;
30
+ border: BorderValue | null;
31
+ margin: ResponsiveValue<PaddingValue> | PaddingValue | null;
32
+ animation: AnimationValue | null;
33
+ visibility: VisibilityValue | null;
34
+ }
35
+ /**
36
+ * Resolve `grid-template-columns` from the column count and distribution preset.
37
+ * Falls back to equal widths when the ratio's segment count doesn't match.
38
+ */
39
+ export declare function resolveColumnsTemplate(count: number, distribution: string): string;
40
+ export declare const ColumnsConfig: ComponentConfig;
@@ -0,0 +1,275 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Columns Component - Puck Configuration (editor)
4
+ *
5
+ * Unlike Grid (a single CSS-grid slot where children auto-place into cells),
6
+ * Columns exposes one independent drop zone PER column — components can be
7
+ * dropped into a specific column. Puck slots are static named fields, so a fixed
8
+ * maximum set of column slots (column1..columnN) is declared and only the first
9
+ * `count` are rendered.
10
+ *
11
+ * Responsive: stacks vertically on mobile, switches to a CSS grid at md+ (≥768px).
12
+ *
13
+ * Width distribution supports equal columns or fr ratios (e.g. 2:1, 1:2, 1:1:2)
14
+ * for asymmetric layouts.
15
+ */ import { useId } from 'react';
16
+ import { dimensionsValueToCSS, marginValueToCSS, paddingValueToCSS, borderValueToCSS, backgroundValueToCSS, responsiveValueToCSS, visibilityValueToCSS } from '../../fields/shared.js';
17
+ import { AnimatedWrapper } from '../AnimatedWrapper.js';
18
+ import { createPaddingField } from '../../fields/PaddingField.js';
19
+ import { createBorderField } from '../../fields/BorderField.js';
20
+ import { createDimensionsField } from '../../fields/DimensionsField.js';
21
+ import { createMarginField } from '../../fields/MarginField.js';
22
+ import { createResetField } from '../../fields/ResetField.js';
23
+ import { createBackgroundField } from '../../fields/BackgroundField.js';
24
+ import { createAnimationField } from '../../fields/AnimationField.js';
25
+ import { createResponsiveField } from '../../fields/ResponsiveField.js';
26
+ import { createResponsiveVisibilityField } from '../../fields/ResponsiveVisibilityField.js';
27
+ export const MAX_COLUMNS = 4;
28
+ const DEFAULT_PADDING = {
29
+ top: 0,
30
+ right: 0,
31
+ bottom: 0,
32
+ left: 0,
33
+ unit: 'px',
34
+ linked: true
35
+ };
36
+ const DEFAULT_DIMENSIONS = {
37
+ mode: 'full',
38
+ alignment: 'center',
39
+ maxWidth: {
40
+ value: 100,
41
+ unit: '%',
42
+ enabled: true
43
+ }
44
+ };
45
+ const defaultProps = {
46
+ column1: [],
47
+ column2: [],
48
+ column3: [],
49
+ column4: [],
50
+ count: 2,
51
+ distribution: 'equal',
52
+ gap: 24,
53
+ background: null,
54
+ customPadding: null,
55
+ dimensions: null,
56
+ border: null,
57
+ margin: null,
58
+ animation: null,
59
+ visibility: null
60
+ };
61
+ /**
62
+ * Resolve `grid-template-columns` from the column count and distribution preset.
63
+ * Falls back to equal widths when the ratio's segment count doesn't match.
64
+ */ export function resolveColumnsTemplate(count, distribution) {
65
+ const safeCount = Math.min(Math.max(Math.round(count) || 2, 1), MAX_COLUMNS);
66
+ if (distribution && distribution !== 'equal') {
67
+ const parts = distribution.split(':').map((p)=>p.trim());
68
+ if (parts.length === safeCount && parts.every((p)=>/^\d+(\.\d+)?$/.test(p))) {
69
+ return parts.map((p)=>`${p}fr`).join(' ');
70
+ }
71
+ }
72
+ return `repeat(${safeCount}, minmax(0, 1fr))`;
73
+ }
74
+ export const ColumnsConfig = {
75
+ label: 'Columns',
76
+ fields: {
77
+ _reset: createResetField({
78
+ defaultProps
79
+ }),
80
+ // One independent drop zone per column. Disallow Section (full-width) inside
81
+ // a column, matching Grid — it would break the column layout.
82
+ column1: {
83
+ type: 'slot',
84
+ disallow: [
85
+ 'Section'
86
+ ]
87
+ },
88
+ column2: {
89
+ type: 'slot',
90
+ disallow: [
91
+ 'Section'
92
+ ]
93
+ },
94
+ column3: {
95
+ type: 'slot',
96
+ disallow: [
97
+ 'Section'
98
+ ]
99
+ },
100
+ column4: {
101
+ type: 'slot',
102
+ disallow: [
103
+ 'Section'
104
+ ]
105
+ },
106
+ // Responsive visibility control
107
+ visibility: createResponsiveVisibilityField({
108
+ label: 'Visibility'
109
+ }),
110
+ count: {
111
+ type: 'select',
112
+ label: 'Number of Columns',
113
+ options: [
114
+ {
115
+ label: '2 Columns',
116
+ value: 2
117
+ },
118
+ {
119
+ label: '3 Columns',
120
+ value: 3
121
+ },
122
+ {
123
+ label: '4 Columns',
124
+ value: 4
125
+ }
126
+ ]
127
+ },
128
+ distribution: {
129
+ type: 'select',
130
+ label: 'Column Widths',
131
+ options: [
132
+ {
133
+ label: 'Equal',
134
+ value: 'equal'
135
+ },
136
+ {
137
+ label: '2 : 1 (wide left)',
138
+ value: '2:1'
139
+ },
140
+ {
141
+ label: '1 : 2 (wide right)',
142
+ value: '1:2'
143
+ },
144
+ {
145
+ label: '3 : 1',
146
+ value: '3:1'
147
+ },
148
+ {
149
+ label: '1 : 3',
150
+ value: '1:3'
151
+ },
152
+ {
153
+ label: '2 : 1 : 1',
154
+ value: '2:1:1'
155
+ },
156
+ {
157
+ label: '1 : 2 : 1 (wide center)',
158
+ value: '1:2:1'
159
+ },
160
+ {
161
+ label: '1 : 1 : 2',
162
+ value: '1:1:2'
163
+ }
164
+ ]
165
+ },
166
+ gap: {
167
+ type: 'number',
168
+ label: 'Gap (px)',
169
+ min: 0
170
+ },
171
+ background: createBackgroundField({
172
+ label: 'Background'
173
+ }),
174
+ border: createBorderField({
175
+ label: 'Border'
176
+ }),
177
+ dimensions: createResponsiveField({
178
+ label: 'Dimensions (Responsive)',
179
+ innerField: (config)=>createDimensionsField(config),
180
+ defaultValue: DEFAULT_DIMENSIONS
181
+ }),
182
+ animation: createAnimationField({
183
+ label: 'Animation'
184
+ }),
185
+ margin: createResponsiveField({
186
+ label: 'Margin (Responsive)',
187
+ innerField: (config)=>createMarginField(config),
188
+ defaultValue: DEFAULT_PADDING
189
+ }),
190
+ customPadding: createResponsiveField({
191
+ label: 'Padding (Responsive)',
192
+ innerField: (config)=>createPaddingField(config),
193
+ defaultValue: DEFAULT_PADDING
194
+ })
195
+ },
196
+ defaultProps,
197
+ render: ({ column1: Column1, column2: Column2, column3: Column3, column4: Column4, count = 2, distribution = 'equal', gap, background, customPadding, dimensions, border, margin, animation, visibility })=>{
198
+ const safeCount = Math.min(Math.max(Math.round(count) || 2, 1), MAX_COLUMNS);
199
+ // Generate unique IDs for CSS targeting
200
+ // eslint-disable-next-line react-hooks/rules-of-hooks
201
+ const uniqueId = useId().replace(/:/g, '');
202
+ const wrapperClass = `puck-columns-${uniqueId}`;
203
+ const contentClass = `puck-columns-content-${uniqueId}`;
204
+ const mediaQueries = [];
205
+ const backgroundStyles = backgroundValueToCSS(background);
206
+ const wrapperStyles = {
207
+ ...backgroundStyles
208
+ };
209
+ const paddingResult = responsiveValueToCSS(customPadding, (v)=>({
210
+ padding: paddingValueToCSS(v)
211
+ }), wrapperClass);
212
+ Object.assign(wrapperStyles, paddingResult.baseStyles);
213
+ if (paddingResult.mediaQueryCSS) mediaQueries.push(paddingResult.mediaQueryCSS);
214
+ const borderStyles = borderValueToCSS(border);
215
+ if (borderStyles) Object.assign(wrapperStyles, borderStyles);
216
+ const marginResult = responsiveValueToCSS(margin, (v)=>({
217
+ margin: marginValueToCSS(v)
218
+ }), wrapperClass);
219
+ Object.assign(wrapperStyles, marginResult.baseStyles);
220
+ if (marginResult.mediaQueryCSS) mediaQueries.push(marginResult.mediaQueryCSS);
221
+ const dimensionsResult = responsiveValueToCSS(dimensions, dimensionsValueToCSS, contentClass);
222
+ const visibilityCSS = visibilityValueToCSS(visibility, wrapperClass);
223
+ if (visibilityCSS) mediaQueries.push(visibilityCSS);
224
+ if (dimensionsResult.mediaQueryCSS) mediaQueries.push(dimensionsResult.mediaQueryCSS);
225
+ // Self-contained CSS grid — does NOT depend on the consumer's Tailwind
226
+ // generating utility classes. Single column on mobile (stacked); switches to
227
+ // the multi-column template at >=768px via the scoped media query below.
228
+ const colsTemplate = resolveColumnsTemplate(safeCount, distribution);
229
+ const gridStyles = {
230
+ display: 'grid',
231
+ gridTemplateColumns: '1fr',
232
+ gap,
233
+ ...dimensionsResult.baseStyles,
234
+ '--cols-template': colsTemplate
235
+ };
236
+ const slots = [
237
+ Column1,
238
+ Column2,
239
+ Column3,
240
+ Column4
241
+ ];
242
+ const allMediaQueryCSS = mediaQueries.join('\n');
243
+ return /*#__PURE__*/ _jsxs(AnimatedWrapper, {
244
+ animation: animation,
245
+ children: [
246
+ allMediaQueryCSS && /*#__PURE__*/ _jsx("style", {
247
+ children: allMediaQueryCSS
248
+ }),
249
+ /*#__PURE__*/ _jsxs("div", {
250
+ className: wrapperClass,
251
+ style: wrapperStyles,
252
+ children: [
253
+ /*#__PURE__*/ _jsx("div", {
254
+ className: contentClass,
255
+ style: gridStyles,
256
+ children: slots.slice(0, safeCount).map((Slot, i)=>{
257
+ const ColumnSlot = Slot;
258
+ return /*#__PURE__*/ _jsx(ColumnSlot, {}, i);
259
+ })
260
+ }),
261
+ /*#__PURE__*/ _jsx("style", {
262
+ children: `
263
+ @media (min-width: 768px) {
264
+ .${contentClass} {
265
+ grid-template-columns: var(--cols-template);
266
+ }
267
+ }
268
+ `
269
+ })
270
+ ]
271
+ })
272
+ ]
273
+ });
274
+ }
275
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Columns Component - Server-safe Puck Configuration
3
+ *
4
+ * Unlike Grid (a single slot styled as CSS grid, where children auto-place into
5
+ * cells), Columns exposes one independent drop zone PER column. Each column is
6
+ * its own slot, so components can be targeted into a specific column.
7
+ *
8
+ * Puck slots are static named fields, so we declare a fixed maximum set of
9
+ * column slots (column1..columnN) and render only the first `count`.
10
+ *
11
+ * Responsive: stacks vertically on mobile (flex column), switches to a CSS grid
12
+ * at md+ (≥768px), matching the Grid component's behavior.
13
+ *
14
+ * This is the server-safe variant (slots only, no editor fields). For the full
15
+ * editor version with fields, use Columns.tsx
16
+ */
17
+ import type { ComponentConfig } from '@puckeditor/core';
18
+ import { type PaddingValue, type BorderValue, type DimensionsValue, type BackgroundValue, type AnimationValue, type ResponsiveValue, type VisibilityValue } from '../../fields/shared.js';
19
+ /** Maximum number of column slots the component declares. */
20
+ export declare const MAX_COLUMNS = 4;
21
+ export type ColumnCount = 2 | 3 | 4;
22
+ export interface ColumnsProps {
23
+ column1: unknown;
24
+ column2: unknown;
25
+ column3: unknown;
26
+ column4: unknown;
27
+ count: ColumnCount;
28
+ /**
29
+ * Column width distribution. 'equal' splits evenly; otherwise a colon-separated
30
+ * fr ratio (e.g. '2:1', '1:2', '1:1:2'). Ratios whose segment count doesn't
31
+ * match `count` fall back to equal.
32
+ */
33
+ distribution: string;
34
+ gap: number;
35
+ background: BackgroundValue | null;
36
+ customPadding: ResponsiveValue<PaddingValue> | PaddingValue | null;
37
+ dimensions: ResponsiveValue<DimensionsValue> | DimensionsValue | null;
38
+ border: BorderValue | null;
39
+ margin: ResponsiveValue<PaddingValue> | PaddingValue | null;
40
+ animation: AnimationValue | null;
41
+ visibility: VisibilityValue | null;
42
+ }
43
+ /**
44
+ * Resolve the `grid-template-columns` value from the column count and the
45
+ * distribution preset. Falls back to equal widths when the ratio doesn't match.
46
+ */
47
+ export declare function resolveColumnsTemplate(count: number, distribution: string): string;
48
+ export declare const ColumnsConfig: ComponentConfig;
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Columns Component - Server-safe Puck Configuration
3
+ *
4
+ * Unlike Grid (a single slot styled as CSS grid, where children auto-place into
5
+ * cells), Columns exposes one independent drop zone PER column. Each column is
6
+ * its own slot, so components can be targeted into a specific column.
7
+ *
8
+ * Puck slots are static named fields, so we declare a fixed maximum set of
9
+ * column slots (column1..columnN) and render only the first `count`.
10
+ *
11
+ * Responsive: stacks vertically on mobile (flex column), switches to a CSS grid
12
+ * at md+ (≥768px), matching the Grid component's behavior.
13
+ *
14
+ * This is the server-safe variant (slots only, no editor fields). For the full
15
+ * editor version with fields, use Columns.tsx
16
+ */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
+ import { dimensionsValueToCSS, marginValueToCSS, paddingValueToCSS, borderValueToCSS, backgroundValueToCSS, responsiveValueToCSS, visibilityValueToCSS } from '../../fields/shared.js';
18
+ import { AnimatedWrapper } from '../AnimatedWrapper.js';
19
+ /** Maximum number of column slots the component declares. */ export const MAX_COLUMNS = 4;
20
+ const defaultProps = {
21
+ column1: [],
22
+ column2: [],
23
+ column3: [],
24
+ column4: [],
25
+ count: 2,
26
+ distribution: 'equal',
27
+ gap: 24,
28
+ background: null,
29
+ customPadding: null,
30
+ dimensions: null,
31
+ border: null,
32
+ margin: null,
33
+ animation: null,
34
+ visibility: null
35
+ };
36
+ // Simple ID generator for server-side rendering
37
+ let idCounter = 0;
38
+ function generateUniqueId() {
39
+ return `c${(++idCounter).toString(36)}${Math.random().toString(36).slice(2, 6)}`;
40
+ }
41
+ /**
42
+ * Resolve the `grid-template-columns` value from the column count and the
43
+ * distribution preset. Falls back to equal widths when the ratio doesn't match.
44
+ */ export function resolveColumnsTemplate(count, distribution) {
45
+ const safeCount = Math.min(Math.max(Math.round(count) || 2, 1), MAX_COLUMNS);
46
+ if (distribution && distribution !== 'equal') {
47
+ const parts = distribution.split(':').map((p)=>p.trim());
48
+ if (parts.length === safeCount && parts.every((p)=>/^\d+(\.\d+)?$/.test(p))) {
49
+ return parts.map((p)=>`${p}fr`).join(' ');
50
+ }
51
+ }
52
+ return `repeat(${safeCount}, minmax(0, 1fr))`;
53
+ }
54
+ export const ColumnsConfig = {
55
+ label: 'Columns',
56
+ fields: {
57
+ column1: {
58
+ type: 'slot'
59
+ },
60
+ column2: {
61
+ type: 'slot'
62
+ },
63
+ column3: {
64
+ type: 'slot'
65
+ },
66
+ column4: {
67
+ type: 'slot'
68
+ }
69
+ },
70
+ defaultProps,
71
+ render: ({ column1: Column1, column2: Column2, column3: Column3, column4: Column4, count = 2, distribution = 'equal', gap, background, customPadding, dimensions, border, margin, animation, visibility })=>{
72
+ const safeCount = Math.min(Math.max(Math.round(count) || 2, 1), MAX_COLUMNS);
73
+ // Generate unique IDs for CSS targeting (server-safe)
74
+ const uniqueId = generateUniqueId();
75
+ const wrapperClass = `puck-columns-${uniqueId}`;
76
+ const contentClass = `puck-columns-content-${uniqueId}`;
77
+ // Collect all media query CSS
78
+ const mediaQueries = [];
79
+ // Generate styles from BackgroundValue
80
+ const backgroundStyles = backgroundValueToCSS(background);
81
+ const wrapperStyles = {
82
+ ...backgroundStyles
83
+ };
84
+ // Padding (responsive)
85
+ const paddingResult = responsiveValueToCSS(customPadding, (v)=>({
86
+ padding: paddingValueToCSS(v)
87
+ }), wrapperClass);
88
+ Object.assign(wrapperStyles, paddingResult.baseStyles);
89
+ if (paddingResult.mediaQueryCSS) mediaQueries.push(paddingResult.mediaQueryCSS);
90
+ // Border
91
+ const borderStyles = borderValueToCSS(border);
92
+ if (borderStyles) Object.assign(wrapperStyles, borderStyles);
93
+ // Margin (responsive)
94
+ const marginResult = responsiveValueToCSS(margin, (v)=>({
95
+ margin: marginValueToCSS(v)
96
+ }), wrapperClass);
97
+ Object.assign(wrapperStyles, marginResult.baseStyles);
98
+ if (marginResult.mediaQueryCSS) mediaQueries.push(marginResult.mediaQueryCSS);
99
+ // Dimensions (responsive)
100
+ const dimensionsResult = responsiveValueToCSS(dimensions, dimensionsValueToCSS, contentClass);
101
+ // Visibility media queries
102
+ const visibilityCSS = visibilityValueToCSS(visibility, wrapperClass);
103
+ if (visibilityCSS) mediaQueries.push(visibilityCSS);
104
+ if (dimensionsResult.mediaQueryCSS) mediaQueries.push(dimensionsResult.mediaQueryCSS);
105
+ // Self-contained CSS grid — does NOT depend on the consumer's Tailwind
106
+ // generating utility classes. Single column on mobile (stacked); switches to
107
+ // the multi-column template at >=768px via the scoped media query below.
108
+ // grid-template-columns is dynamic, so drive it from a CSS var.
109
+ const colsTemplate = resolveColumnsTemplate(safeCount, distribution);
110
+ const gridStyles = {
111
+ display: 'grid',
112
+ gridTemplateColumns: '1fr',
113
+ gap,
114
+ ...dimensionsResult.baseStyles,
115
+ '--cols-template': colsTemplate
116
+ };
117
+ const slots = [
118
+ Column1,
119
+ Column2,
120
+ Column3,
121
+ Column4
122
+ ];
123
+ const allMediaQueryCSS = mediaQueries.join('\n');
124
+ return /*#__PURE__*/ _jsxs(AnimatedWrapper, {
125
+ animation: animation,
126
+ children: [
127
+ allMediaQueryCSS && /*#__PURE__*/ _jsx("style", {
128
+ children: allMediaQueryCSS
129
+ }),
130
+ /*#__PURE__*/ _jsxs("div", {
131
+ className: wrapperClass,
132
+ style: wrapperStyles,
133
+ children: [
134
+ /*#__PURE__*/ _jsx("div", {
135
+ className: contentClass,
136
+ style: gridStyles,
137
+ children: slots.slice(0, safeCount).map((Slot, i)=>{
138
+ const ColumnSlot = Slot;
139
+ return /*#__PURE__*/ _jsx(ColumnSlot, {}, i);
140
+ })
141
+ }),
142
+ /*#__PURE__*/ _jsx("style", {
143
+ children: `
144
+ @media (min-width: 768px) {
145
+ .${contentClass} {
146
+ grid-template-columns: var(--cols-template);
147
+ }
148
+ }
149
+ `
150
+ })
151
+ ]
152
+ })
153
+ ]
154
+ });
155
+ }
156
+ };
@@ -14,7 +14,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  * - gap: Different gap at different breakpoints
15
15
  * - visibility: Show/hide at different breakpoints
16
16
  */ import { useId } from 'react';
17
- import { cn, dimensionsValueToCSS, marginValueToCSS, paddingValueToCSS, borderValueToCSS, backgroundValueToCSS, responsiveValueToCSS, visibilityValueToCSS } from '../../fields/shared.js';
17
+ import { dimensionsValueToCSS, marginValueToCSS, paddingValueToCSS, borderValueToCSS, backgroundValueToCSS, responsiveValueToCSS, visibilityValueToCSS } from '../../fields/shared.js';
18
18
  import { AnimatedWrapper } from '../AnimatedWrapper.js';
19
19
  import { createPaddingField } from '../../fields/PaddingField.js';
20
20
  import { createBorderField } from '../../fields/BorderField.js';
@@ -176,19 +176,18 @@ export const GridConfig = {
176
176
  if (visibilityCSS) {
177
177
  mediaQueries.push(visibilityCSS);
178
178
  }
179
- // Tailwind classes for responsive grid: flex column on mobile, grid on md+
180
- const contentClasses = cn('flex flex-col w-full', 'md:grid', contentClass);
181
- // Dynamic styles that need inline (user-controlled values: gap, columns)
182
- const contentStyles = {
183
- gap,
184
- ...dimensionsResult.baseStyles
185
- };
186
179
  if (dimensionsResult.mediaQueryCSS) {
187
180
  mediaQueries.push(dimensionsResult.mediaQueryCSS);
188
181
  }
189
- // Grid template columns must be inline since numColumns is dynamic
182
+ // Self-contained CSS grid does NOT depend on the consumer's Tailwind
183
+ // generating utility classes. Single column on mobile (children stacked);
184
+ // switches to the multi-column track at >=768px via the scoped media query.
185
+ // grid-template-columns is dynamic, so drive the column count from a CSS var.
190
186
  const gridStyles = {
191
- ...contentStyles,
187
+ display: 'grid',
188
+ gridTemplateColumns: '1fr',
189
+ gap,
190
+ ...dimensionsResult.baseStyles,
192
191
  '--grid-cols': numColumns
193
192
  };
194
193
  // Combine all media queries
@@ -204,13 +203,13 @@ export const GridConfig = {
204
203
  style: wrapperStyles,
205
204
  children: [
206
205
  /*#__PURE__*/ _jsx(Content, {
207
- className: contentClasses,
206
+ className: contentClass,
208
207
  style: gridStyles
209
208
  }),
210
209
  /*#__PURE__*/ _jsx("style", {
211
210
  children: `
212
211
  @media (min-width: 768px) {
213
- .flex.md\\:grid {
212
+ .${contentClass} {
214
213
  grid-template-columns: repeat(var(--grid-cols), 1fr);
215
214
  }
216
215
  }
@@ -14,7 +14,7 @@
14
14
  * - margin: Different margins at different breakpoints
15
15
  * - visibility: Show/hide at different breakpoints
16
16
  */ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
- import { cn, dimensionsValueToCSS, marginValueToCSS, paddingValueToCSS, borderValueToCSS, backgroundValueToCSS, responsiveValueToCSS, visibilityValueToCSS } from '../../fields/shared.js';
17
+ import { dimensionsValueToCSS, marginValueToCSS, paddingValueToCSS, borderValueToCSS, backgroundValueToCSS, responsiveValueToCSS, visibilityValueToCSS } from '../../fields/shared.js';
18
18
  import { AnimatedWrapper } from '../AnimatedWrapper.js';
19
19
  // Simple ID generator for server-side rendering
20
20
  let idCounter = 0;
@@ -85,19 +85,18 @@ export const GridConfig = {
85
85
  if (visibilityCSS) {
86
86
  mediaQueries.push(visibilityCSS);
87
87
  }
88
- // Tailwind classes for responsive grid: flex column on mobile, grid on md+
89
- const contentClasses = cn('flex flex-col w-full', 'md:grid', contentClass);
90
- // Dynamic styles that need inline (user-controlled values: gap, columns)
91
- const contentStyles = {
92
- gap,
93
- ...dimensionsResult.baseStyles
94
- };
95
88
  if (dimensionsResult.mediaQueryCSS) {
96
89
  mediaQueries.push(dimensionsResult.mediaQueryCSS);
97
90
  }
98
- // Grid template columns must be inline since numColumns is dynamic
91
+ // Self-contained CSS grid does NOT depend on the consumer's Tailwind
92
+ // generating utility classes. Single column on mobile (children stacked);
93
+ // switches to the multi-column track at >=768px via the scoped media query.
94
+ // grid-template-columns is dynamic, so drive the column count from a CSS var.
99
95
  const gridStyles = {
100
- ...contentStyles,
96
+ display: 'grid',
97
+ gridTemplateColumns: '1fr',
98
+ gap,
99
+ ...dimensionsResult.baseStyles,
101
100
  '--grid-cols': numColumns
102
101
  };
103
102
  // Combine all media queries
@@ -115,13 +114,13 @@ export const GridConfig = {
115
114
  style: wrapperStyles,
116
115
  children: [
117
116
  /*#__PURE__*/ _jsx(ContentSlot, {
118
- className: contentClasses,
117
+ className: contentClass,
119
118
  style: gridStyles
120
119
  }),
121
120
  /*#__PURE__*/ _jsx("style", {
122
121
  children: `
123
122
  @media (min-width: 768px) {
124
- .flex.md\\:grid {
123
+ .${contentClass} {
125
124
  grid-template-columns: repeat(var(--grid-cols), 1fr);
126
125
  }
127
126
  }
@@ -94,6 +94,7 @@ export declare const editorConfig: {
94
94
  Container: ComponentConfig<any>;
95
95
  Flex: ComponentConfig<any>;
96
96
  Grid: ComponentConfig<any>;
97
+ Columns: ComponentConfig<any>;
97
98
  Section: ComponentConfig<any>;
98
99
  Spacer: ComponentConfig<any>;
99
100
  Template: ComponentConfig<any>;
@@ -6,6 +6,7 @@ import { lockedSlugField, lockedHomepageField } from '../fields/LockedField.js';
6
6
  import { ContainerConfig } from '../components/layout/Container.js';
7
7
  import { FlexConfig } from '../components/layout/Flex.js';
8
8
  import { GridConfig } from '../components/layout/Grid.js';
9
+ import { ColumnsConfig } from '../components/layout/Columns.js';
9
10
  import { SectionConfig } from '../components/layout/Section.js';
10
11
  import { SpacerConfig } from '../components/layout/Spacer.js';
11
12
  import { TemplateConfig } from '../components/layout/Template.js';
@@ -146,6 +147,7 @@ export const editorConfig = {
146
147
  'Container',
147
148
  'Flex',
148
149
  'Grid',
150
+ 'Columns',
149
151
  'Section',
150
152
  'Spacer',
151
153
  'Template'
@@ -181,6 +183,7 @@ export const editorConfig = {
181
183
  Container: ContainerConfig,
182
184
  Flex: FlexConfig,
183
185
  Grid: GridConfig,
186
+ Columns: ColumnsConfig,
184
187
  Section: SectionConfig,
185
188
  Spacer: SpacerConfig,
186
189
  Template: TemplateConfig,
@@ -9,6 +9,7 @@ import { DEFAULT_LAYOUTS, layoutsToOptions } from '../layouts/index.js';
9
9
  import { ContainerConfig } from '../components/layout/Container.server.js';
10
10
  import { FlexConfig } from '../components/layout/Flex.server.js';
11
11
  import { GridConfig } from '../components/layout/Grid.server.js';
12
+ import { ColumnsConfig } from '../components/layout/Columns.server.js';
12
13
  import { SectionConfig } from '../components/layout/Section.server.js';
13
14
  import { SpacerConfig } from '../components/layout/Spacer.server.js';
14
15
  import { TemplateServerConfig } from '../components/layout/Template.server.js';
@@ -75,6 +76,7 @@ import { AccordionConfig } from '../components/interactive/Accordion.server.js';
75
76
  'Container',
76
77
  'Flex',
77
78
  'Grid',
79
+ 'Columns',
78
80
  'Section',
79
81
  'Spacer',
80
82
  'Template'
@@ -110,6 +112,7 @@ import { AccordionConfig } from '../components/interactive/Accordion.server.js';
110
112
  Container: ContainerConfig,
111
113
  Flex: FlexConfig,
112
114
  Grid: GridConfig,
115
+ Columns: ColumnsConfig,
113
116
  Section: SectionConfig,
114
117
  Spacer: SpacerConfig,
115
118
  Template: TemplateServerConfig,
@@ -244,6 +244,7 @@ export declare const fullConfig: {
244
244
  Container: ComponentConfig<any>;
245
245
  Flex: ComponentConfig<any>;
246
246
  Grid: ComponentConfig<any>;
247
+ Columns: ComponentConfig<any>;
247
248
  Section: ComponentConfig<any>;
248
249
  Spacer: ComponentConfig<any>;
249
250
  Template: ComponentConfig<any>;
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  // Import component configs
4
- import { ContainerConfig, FlexConfig, GridConfig, SectionConfig, SpacerConfig, TemplateConfig, HeadingConfig, TextConfig, RichTextEditorConfig, ImageConfig, ButtonConfig, CardConfig, DividerConfig, AccordionConfig } from '../components/exports.js';
4
+ import { ContainerConfig, FlexConfig, GridConfig, ColumnsConfig, SectionConfig, SpacerConfig, TemplateConfig, HeadingConfig, TextConfig, RichTextEditorConfig, ImageConfig, ButtonConfig, CardConfig, DividerConfig, AccordionConfig } from '../components/exports.js';
5
5
  // Import field factories for root config
6
6
  import { createBackgroundField } from '../fields/BackgroundField.js';
7
7
  import { lockedSlugField, lockedHomepageField } from '../fields/LockedField.js';
@@ -278,6 +278,7 @@ import { createSlugPreviewField } from '../fields/SlugPreviewField.js';
278
278
  'Container',
279
279
  'Flex',
280
280
  'Grid',
281
+ 'Columns',
281
282
  'Section',
282
283
  'Spacer',
283
284
  'Template'
@@ -313,6 +314,7 @@ import { createSlugPreviewField } from '../fields/SlugPreviewField.js';
313
314
  Container: ContainerConfig,
314
315
  Flex: FlexConfig,
315
316
  Grid: GridConfig,
317
+ Columns: ColumnsConfig,
316
318
  Section: SectionConfig,
317
319
  Spacer: SpacerConfig,
318
320
  Template: TemplateConfig,
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.6.26";
1
+ export declare const VERSION = "0.6.28";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by scripts/generate-version.js - do not edit manually
2
- export const VERSION = '0.6.26';
2
+ export const VERSION = '0.6.28';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delmaredigital/payload-puck",
3
- "version": "0.6.26",
3
+ "version": "0.6.28",
4
4
  "description": "Puck visual page builder plugin for Payload CMS",
5
5
  "type": "module",
6
6
  "license": "MIT",