@vitus-labs/coolgrid 2.0.0-alpha.8 → 2.0.0-beta.0

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @vitus-labs/coolgrid
2
2
 
3
- Responsive grid system for React and styled-components.
3
+ Responsive grid system for React.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@vitus-labs/coolgrid)](https://www.npmjs.com/package/@vitus-labs/coolgrid)
6
6
  [![license](https://img.shields.io/npm/l/@vitus-labs/coolgrid)](https://github.com/vitus-labs/ui-system/blob/main/LICENSE)
@@ -20,7 +20,7 @@ Bootstrap-inspired Container / Row / Col grid with context-cascading configurati
20
20
  ## Installation
21
21
 
22
22
  ```bash
23
- npm install @vitus-labs/coolgrid @vitus-labs/core @vitus-labs/unistyle styled-components
23
+ npm install @vitus-labs/coolgrid @vitus-labs/core @vitus-labs/unistyle
24
24
  ```
25
25
 
26
26
  ## Quick Start
@@ -213,6 +213,10 @@ All numeric props support three formats:
213
213
  <Col size={{ xs: 12, md: 6, lg: 4 }} />
214
214
  ```
215
215
 
216
+ ## React Native
217
+
218
+ Coolgrid includes native components (`Col.native.tsx`, `Row.native.tsx`) that use `onLayout` measurement instead of CSS `calc()`. Works automatically when initialized with `@vitus-labs/connector-native`.
219
+
216
220
  ## Peer Dependencies
217
221
 
218
222
  | Package | Version |
@@ -220,7 +224,7 @@ All numeric props support three formats:
220
224
  | react | >= 19 |
221
225
  | @vitus-labs/core | * |
222
226
  | @vitus-labs/unistyle | * |
223
- | styled-components | >= 6 |
227
+ | react-native | >= 0.76 (optional) |
224
228
 
225
229
  ## License
226
230
 
package/lib/index.js CHANGED
@@ -84,12 +84,14 @@ const widthStyles = ({ size, columns, gap, RNparentWidth }, { rootSize }) => {
84
84
  const c = columns;
85
85
  const g = gap;
86
86
  const width = s / c * 100;
87
- const val = hasValue(gap) ? `calc(${width}% - ${g}px)` : `${width}%`;
87
+ const v = value(hasValue(gap) ? `calc(${width}% - ${g}px)` : `${width}%`, rootSize);
88
88
  return css$2`
89
89
  flex-grow: 0;
90
90
  flex-shrink: 0;
91
- max-width: ${value(val, rootSize)};
92
- flex-basis: ${value(val, rootSize)};
91
+ ${css$2`
92
+ max-width: ${v};
93
+ flex-basis: ${v};
94
+ `}
93
95
  `;
94
96
  };
95
97
  /** Applies half of the given value as either margin or padding (used for gap and padding distribution). */
@@ -107,7 +109,7 @@ const spacingStyles$1 = (type, param, rootSize) => {
107
109
  const styles$2 = ({ theme, css, rootSize }) => {
108
110
  const { size, columns, gap, padding, extraStyles, RNparentWidth } = theme;
109
111
  if (isVisible(size)) return css`
110
- left: initial;
112
+ ${"left: initial;"}
111
113
  position: relative;
112
114
  ${widthStyles({
113
115
  size,
@@ -121,7 +123,7 @@ const styles$2 = ({ theme, css, rootSize }) => {
121
123
  `;
122
124
  return css`
123
125
  left: -9999px;
124
- position: fixed;
126
+ position: ${"fixed"};
125
127
  margin: 0;
126
128
  padding: 0;
127
129
  `;
@@ -129,14 +131,14 @@ const styles$2 = ({ theme, css, rootSize }) => {
129
131
  var styled_default$2 = styled$2(component$2)`
130
132
  ${css$2`
131
133
  box-sizing: border-box;
132
- `};
134
+ justify-content: stretch;
135
+ `}
133
136
 
134
137
  position: relative;
135
138
  display: flex;
136
139
  flex-basis: 0;
137
140
  flex-grow: 1;
138
141
  flex-direction: column;
139
- justify-content: stretch;
140
142
 
141
143
  ${makeItResponsive({
142
144
  key: "$coolgrid",
@@ -194,21 +196,23 @@ var Col_default = Component$2;
194
196
  //#region src/Container/styled.ts
195
197
  const { styled: styled$1, css: css$1, component: component$1 } = config;
196
198
  /** Responsive styles that apply the container's max-width and any extra CSS at each breakpoint. */
197
- const styles$1 = ({ theme: t, css, rootSize }) => css`
198
- max-width: ${value(t.width, rootSize)};
199
- ${extendCss(t.extraStyles)};
200
- `;
199
+ const styles$1 = ({ theme: t, css, rootSize }) => {
200
+ const w = t.width != null && typeof t.width !== "object" ? t.width : null;
201
+ return css`
202
+ ${w != null ? `max-width: ${value(w, rootSize)};` : ""};
203
+ ${extendCss(t.extraStyles)};
204
+ `;
205
+ };
201
206
  /** Styled Container element. Centered via auto margins with responsive max-width. */
202
207
  var styled_default$1 = styled$1(component$1)`
203
- ${css$1`
204
- box-sizing: border-box;
205
- `};
206
-
207
208
  display: flex;
208
- width: 100%;
209
209
  flex-direction: column;
210
- margin-right: auto;
211
- margin-left: auto;
210
+ ${css$1`
211
+ box-sizing: border-box;
212
+ width: 100%;
213
+ margin-right: auto;
214
+ margin-left: auto;
215
+ `}
212
216
 
213
217
  ${makeItResponsive({
214
218
  key: "$coolgrid",
@@ -228,7 +232,7 @@ var styled_default$1 = styled$1(component$1)`
228
232
  */
229
233
  const DEV_PROPS$1 = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "container" } : {};
230
234
  const Component$1 = ({ children, component, css, width, ...props }) => {
231
- const { containerWidth = {}, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
235
+ const { containerWidth, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
232
236
  const context = useMemo(() => ({
233
237
  columns,
234
238
  size,
@@ -289,8 +293,8 @@ const spacingStyles = ({ gap, gutter }, { rootSize }) => {
289
293
  const getValue = (param) => value(param, rootSize);
290
294
  const spacingX = g / 2 * -1;
291
295
  return css`
292
- margin: ${getValue(isNumber(gutter) ? gutter - g / 2 : g / 2)} ${getValue(spacingX)};
293
- `;
296
+ margin: ${getValue(isNumber(gutter) ? gutter - g / 2 : g / 2)} ${getValue(spacingX)};
297
+ `;
294
298
  };
295
299
  /** Maps the contentAlignX prop to a CSS justify-content value. */
296
300
  const contentAlign = (align) => {
@@ -1,5 +1,5 @@
1
1
  import { ALIGN_CONTENT_MAP_X, Provider, context, extendCss, makeItResponsive, value } from "@vitus-labs/unistyle";
2
- import { createContext, useContext, useMemo } from "react";
2
+ import { createContext, useCallback, useContext, useMemo, useState } from "react";
3
3
  import { config, get, omit, pick } from "@vitus-labs/core";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
 
@@ -83,13 +83,15 @@ const widthStyles = ({ size, columns, gap, RNparentWidth }, { rootSize }) => {
83
83
  const s = size;
84
84
  const c = columns;
85
85
  const g = gap;
86
+ if (!RNparentWidth) return "";
86
87
  const width = RNparentWidth / c * s;
87
- const val = hasValue(gap) ? width - g : width;
88
88
  return css$2`
89
89
  flex-grow: 0;
90
90
  flex-shrink: 0;
91
- max-width: ${value(val, rootSize)};
92
- flex-basis: ${value(val, rootSize)};
91
+ ${css$2`
92
+ width: ${value(hasValue(gap) ? Math.max(0, width - g) : width, rootSize)};
93
+ flex-basis: auto;
94
+ `}
93
95
  `;
94
96
  };
95
97
  /** Applies half of the given value as either margin or padding (used for gap and padding distribution). */
@@ -107,7 +109,7 @@ const spacingStyles$1 = (type, param, rootSize) => {
107
109
  const styles$2 = ({ theme, css, rootSize }) => {
108
110
  const { size, columns, gap, padding, extraStyles, RNparentWidth } = theme;
109
111
  if (isVisible(size)) return css`
110
- left: initial;
112
+ ${""}
111
113
  position: relative;
112
114
  ${widthStyles({
113
115
  size,
@@ -121,20 +123,19 @@ const styles$2 = ({ theme, css, rootSize }) => {
121
123
  `;
122
124
  return css`
123
125
  left: -9999px;
124
- position: fixed;
126
+ position: ${"absolute"};
125
127
  margin: 0;
126
128
  padding: 0;
127
129
  `;
128
130
  };
129
131
  var styled_default$2 = styled$2(component$2)`
130
- ${false};
132
+ ${false}
131
133
 
132
134
  position: relative;
133
135
  display: flex;
134
136
  flex-basis: 0;
135
137
  flex-grow: 1;
136
138
  flex-direction: column;
137
- justify-content: stretch;
138
139
 
139
140
  ${makeItResponsive({
140
141
  key: "$coolgrid",
@@ -145,29 +146,32 @@ var styled_default$2 = styled$2(component$2)`
145
146
  `;
146
147
 
147
148
  //#endregion
148
- //#region src/Col/component.tsx
149
+ //#region src/Col/component.native.tsx
149
150
  /**
150
- * Col (column) component that reads grid settings from RowContext
151
- * (columns, gap, gutter) and calculates its own width as a fraction
152
- * of the total columns. Supports responsive size, padding, and visibility.
151
+ * Native Col component that reads RNparentWidth from RowContext
152
+ * and passes it into the styled component so column widths can be
153
+ * computed as absolute pixels (CSS calc() is unavailable on RN).
153
154
  */
154
- const DEV_PROPS$2 = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "col" } : {};
155
155
  const Component$2 = ({ children, component, css, ...props }) => {
156
+ const parentCtx = useContext(RowContext_default);
156
157
  const { colCss, colComponent, columns, gap, size, padding } = useGridContext({
157
- ...useContext(RowContext_default),
158
+ ...parentCtx,
158
159
  ...props
159
160
  });
161
+ const RNparentWidth = parentCtx.RNparentWidth ?? 0;
160
162
  const finalProps = useMemo(() => ({ $coolgrid: {
161
163
  columns,
162
164
  gap,
163
165
  size,
164
166
  padding,
167
+ RNparentWidth,
165
168
  extraStyles: css ?? colCss
166
169
  } }), [
167
170
  columns,
168
171
  gap,
169
172
  size,
170
173
  padding,
174
+ RNparentWidth,
171
175
  css,
172
176
  colCss
173
177
  ]);
@@ -175,7 +179,6 @@ const Component$2 = ({ children, component, css, ...props }) => {
175
179
  ...omitCtxKeys(props),
176
180
  as: component ?? colComponent,
177
181
  ...finalProps,
178
- ...DEV_PROPS$2,
179
182
  children
180
183
  });
181
184
  };
@@ -192,19 +195,18 @@ var Col_default = Component$2;
192
195
  //#region src/Container/styled.ts
193
196
  const { styled: styled$1, css: css$1, component: component$1 } = config;
194
197
  /** Responsive styles that apply the container's max-width and any extra CSS at each breakpoint. */
195
- const styles$1 = ({ theme: t, css, rootSize }) => css`
196
- max-width: ${value(t.width, rootSize)};
197
- ${extendCss(t.extraStyles)};
198
- `;
198
+ const styles$1 = ({ theme: t, css, rootSize }) => {
199
+ const w = t.width != null && typeof t.width !== "object" ? t.width : null;
200
+ return css`
201
+ ${w != null ? `max-width: ${value(w, rootSize)};` : ""};
202
+ ${extendCss(t.extraStyles)};
203
+ `;
204
+ };
199
205
  /** Styled Container element. Centered via auto margins with responsive max-width. */
200
206
  var styled_default$1 = styled$1(component$1)`
201
- ${false};
202
-
203
207
  display: flex;
204
- width: 100%;
205
208
  flex-direction: column;
206
- margin-right: auto;
207
- margin-left: auto;
209
+ ${false}
208
210
 
209
211
  ${makeItResponsive({
210
212
  key: "$coolgrid",
@@ -222,9 +224,9 @@ var styled_default$1 = styled$1(component$1)`
222
224
  * components via ContainerContext, and renders a styled wrapper with
223
225
  * responsive max-width.
224
226
  */
225
- const DEV_PROPS$1 = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "container" } : {};
227
+ const DEV_PROPS = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "container" } : {};
226
228
  const Component$1 = ({ children, component, css, width, ...props }) => {
227
- const { containerWidth = {}, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
229
+ const { containerWidth, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
228
230
  const context = useMemo(() => ({
229
231
  columns,
230
232
  size,
@@ -260,7 +262,7 @@ const Component$1 = ({ children, component, css, width, ...props }) => {
260
262
  ...omitCtxKeys(props),
261
263
  as: component,
262
264
  ...finalProps,
263
- ...DEV_PROPS$1,
265
+ ...DEV_PROPS,
264
266
  children: /* @__PURE__ */ jsx(ContainerContext_default.Provider, {
265
267
  value: context,
266
268
  children
@@ -284,9 +286,13 @@ const spacingStyles = ({ gap, gutter }, { rootSize }) => {
284
286
  const g = gap;
285
287
  const getValue = (param) => value(param, rootSize);
286
288
  const spacingX = g / 2 * -1;
289
+ const spacingY = isNumber(gutter) ? gutter - g / 2 : g / 2;
287
290
  return css`
288
- margin: ${getValue(isNumber(gutter) ? gutter - g / 2 : g / 2)} ${getValue(spacingX)};
289
- `;
291
+ margin-top: ${getValue(spacingY)};
292
+ margin-bottom: ${getValue(spacingY)};
293
+ margin-left: ${getValue(spacingX)};
294
+ margin-right: ${getValue(spacingX)};
295
+ `;
290
296
  };
291
297
  /** Maps the contentAlignX prop to a CSS justify-content value. */
292
298
  const contentAlign = (align) => {
@@ -324,17 +330,17 @@ var styled_default = styled(component)`
324
330
  `;
325
331
 
326
332
  //#endregion
327
- //#region src/Row/component.tsx
333
+ //#region src/Row/component.native.tsx
328
334
  /**
329
- * Row component that reads inherited config from ContainerContext, merges
330
- * it with its own props, and provides the resolved grid settings (columns,
331
- * gap, gutter) to Col children via RowContext. Renders a flex-wrap container
332
- * with negative margins to offset column gutters.
335
+ * Native Row component that measures its own width via onLayout and passes
336
+ * it as RNparentWidth through RowContext so Col children can compute
337
+ * absolute pixel widths (CSS calc() is unavailable on React Native).
333
338
  */
334
- const DEV_PROPS = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "row" } : {};
335
339
  const Component = ({ children, component, css, contentAlignX: rowAlignX, ...props }) => {
340
+ const parentCtx = useContext(ContainerContext_default);
341
+ const [parentWidth, setParentWidth] = useState(0);
336
342
  const { columns, gap, gutter, rowComponent, rowCss, contentAlignX, containerWidth, size, padding, colCss, colComponent } = useGridContext({
337
- ...useContext(ContainerContext_default),
343
+ ...parentCtx,
338
344
  ...props
339
345
  });
340
346
  const context = useMemo(() => ({
@@ -345,7 +351,8 @@ const Component = ({ children, component, css, contentAlignX: rowAlignX, ...prop
345
351
  colComponent,
346
352
  columns,
347
353
  gap,
348
- gutter
354
+ gutter,
355
+ RNparentWidth: parentWidth
349
356
  }), [
350
357
  containerWidth,
351
358
  size,
@@ -354,7 +361,8 @@ const Component = ({ children, component, css, contentAlignX: rowAlignX, ...prop
354
361
  colComponent,
355
362
  columns,
356
363
  gap,
357
- gutter
364
+ gutter,
365
+ parentWidth
358
366
  ]);
359
367
  const finalProps = useMemo(() => ({ $coolgrid: {
360
368
  contentAlignX: rowAlignX || contentAlignX,
@@ -371,11 +379,15 @@ const Component = ({ children, component, css, contentAlignX: rowAlignX, ...prop
371
379
  css,
372
380
  rowCss
373
381
  ]);
382
+ const onLayout = useCallback((e) => {
383
+ const newWidth = e?.nativeEvent?.layout?.width;
384
+ if (newWidth != null) setParentWidth((prev) => prev === newWidth ? prev : newWidth);
385
+ }, []);
374
386
  return /* @__PURE__ */ jsx(styled_default, {
375
387
  ...omitCtxKeys(props),
376
388
  as: component || rowComponent,
377
389
  ...finalProps,
378
- ...DEV_PROPS,
390
+ onLayout,
379
391
  children: /* @__PURE__ */ jsx(RowContext_default.Provider, {
380
392
  value: context,
381
393
  children
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitus-labs/coolgrid",
3
- "version": "2.0.0-alpha.8+e1d1ee5",
3
+ "version": "2.0.0-beta.0",
4
4
  "license": "MIT",
5
5
  "author": "Vit Bokisch <vit@bokisch.cz>",
6
6
  "maintainers": [
@@ -10,11 +10,13 @@
10
10
  "sideEffects": false,
11
11
  "exports": {
12
12
  "source": "./src/index.ts",
13
+ "react-native": "./lib/vitus-labs-coolgrid.native.js",
13
14
  "import": "./lib/index.js",
14
15
  "types": "./lib/index.d.ts"
15
16
  },
16
17
  "types": "./lib/index.d.ts",
17
18
  "react-native": "./lib/vitus-labs-coolgrid.native.js",
19
+ "main": "./lib/index.js",
18
20
  "files": [
19
21
  "lib",
20
22
  "!lib/**/*.map",
@@ -56,19 +58,27 @@
56
58
  "test:coverage": "vitest run --coverage",
57
59
  "test:watch": "vitest",
58
60
  "cover": "coveralls < .coverage/lcov.info",
59
- "typecheck": "tsc --noEmit"
61
+ "typecheck": "tsc --noEmit",
62
+ "version": "node ../../scripts/sync-peer-deps.mjs"
60
63
  },
61
64
  "peerDependencies": {
62
- "@vitus-labs/core": "^1.4.0",
63
- "@vitus-labs/unistyle": "^1.4.0",
64
- "react": ">= 19"
65
+ "@vitus-labs/core": "2.0.0-alpha.27",
66
+ "@vitus-labs/unistyle": "2.0.0-alpha.27",
67
+ "react": ">= 19",
68
+ "react-native": ">= 0.76"
69
+ },
70
+ "peerDependenciesMeta": {
71
+ "react-native": {
72
+ "optional": true
73
+ }
65
74
  },
66
75
  "devDependencies": {
67
- "@vitus-labs/core": "2.0.0-alpha.8+e1d1ee5",
68
- "@vitus-labs/tools-rolldown": "^1.6.0",
69
- "@vitus-labs/tools-storybook": "^1.6.0",
70
- "@vitus-labs/tools-typescript": "^1.6.0",
71
- "@vitus-labs/unistyle": "2.0.0-alpha.8+e1d1ee5"
76
+ "@vitus-labs/core": "2.0.0-beta.0",
77
+ "@vitus-labs/tools-rolldown": "1.10.0",
78
+ "@vitus-labs/tools-storybook": "1.10.0",
79
+ "@vitus-labs/tools-typescript": "1.10.0",
80
+ "@vitus-labs/unistyle": "2.0.0-beta.0",
81
+ "react-native": ">=0.76.0"
72
82
  },
73
- "gitHead": "e1d1ee532fb024b6274ae33a3e42389f4e9858ab"
83
+ "gitHead": "dd8b9f356086ecd8bfb69c87fcad1e8bfa9ab1f4"
74
84
  }