@vitus-labs/coolgrid 2.0.0-alpha.9 → 2.0.0-beta.1

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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Provider, extendCss } from "@vitus-labs/unistyle";
2
+ import { BreakpointKeys } from "@vitus-labs/core";
2
3
  import { ComponentType, FC, ReactNode } from "react";
3
- import { BreakpointKeys, config } from "@vitus-labs/core";
4
4
 
5
5
  //#region src/types.d.ts
6
6
  type CreateValueType<T> = T | T[] | Partial<Record<BreakpointKeys, T>>;
package/lib/index.js CHANGED
@@ -49,11 +49,13 @@ const getGridContext = (props = {}, theme = {}) => ({
49
49
  });
50
50
  const useGridContext = (props) => {
51
51
  const { theme } = useContext(context);
52
- const ctxProps = pickThemeProps(props, CONTEXT_KEYS);
53
- return {
54
- ...getGridContext(ctxProps, theme),
55
- ...ctxProps
56
- };
52
+ return useMemo(() => {
53
+ const ctxProps = pickThemeProps(props, CONTEXT_KEYS);
54
+ return {
55
+ ...getGridContext(ctxProps, theme),
56
+ ...ctxProps
57
+ };
58
+ }, [props, theme]);
57
59
  };
58
60
 
59
61
  //#endregion
@@ -84,12 +86,14 @@ const widthStyles = ({ size, columns, gap, RNparentWidth }, { rootSize }) => {
84
86
  const c = columns;
85
87
  const g = gap;
86
88
  const width = s / c * 100;
87
- const val = hasValue(gap) ? `calc(${width}% - ${g}px)` : `${width}%`;
89
+ const v = value(hasValue(gap) ? `calc(${width}% - ${g}px)` : `${width}%`, rootSize);
88
90
  return css$2`
89
91
  flex-grow: 0;
90
92
  flex-shrink: 0;
91
- max-width: ${value(val, rootSize)};
92
- flex-basis: ${value(val, rootSize)};
93
+ ${css$2`
94
+ max-width: ${v};
95
+ flex-basis: ${v};
96
+ `}
93
97
  `;
94
98
  };
95
99
  /** Applies half of the given value as either margin or padding (used for gap and padding distribution). */
@@ -107,7 +111,7 @@ const spacingStyles$1 = (type, param, rootSize) => {
107
111
  const styles$2 = ({ theme, css, rootSize }) => {
108
112
  const { size, columns, gap, padding, extraStyles, RNparentWidth } = theme;
109
113
  if (isVisible(size)) return css`
110
- left: initial;
114
+ ${"left: initial;"}
111
115
  position: relative;
112
116
  ${widthStyles({
113
117
  size,
@@ -121,7 +125,7 @@ const styles$2 = ({ theme, css, rootSize }) => {
121
125
  `;
122
126
  return css`
123
127
  left: -9999px;
124
- position: fixed;
128
+ position: ${"fixed"};
125
129
  margin: 0;
126
130
  padding: 0;
127
131
  `;
@@ -129,14 +133,14 @@ const styles$2 = ({ theme, css, rootSize }) => {
129
133
  var styled_default$2 = styled$2(component$2)`
130
134
  ${css$2`
131
135
  box-sizing: border-box;
132
- `};
136
+ justify-content: stretch;
137
+ `}
133
138
 
134
139
  position: relative;
135
140
  display: flex;
136
141
  flex-basis: 0;
137
142
  flex-grow: 1;
138
143
  flex-direction: column;
139
- justify-content: stretch;
140
144
 
141
145
  ${makeItResponsive({
142
146
  key: "$coolgrid",
@@ -194,21 +198,23 @@ var Col_default = Component$2;
194
198
  //#region src/Container/styled.ts
195
199
  const { styled: styled$1, css: css$1, component: component$1 } = config;
196
200
  /** 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
- `;
201
+ const styles$1 = ({ theme: t, css, rootSize }) => {
202
+ const w = t.width != null && typeof t.width !== "object" ? t.width : null;
203
+ return css`
204
+ ${w != null ? `max-width: ${value(w, rootSize)};` : ""};
205
+ ${extendCss(t.extraStyles)};
206
+ `;
207
+ };
201
208
  /** Styled Container element. Centered via auto margins with responsive max-width. */
202
209
  var styled_default$1 = styled$1(component$1)`
203
- ${css$1`
204
- box-sizing: border-box;
205
- `};
206
-
207
210
  display: flex;
208
- width: 100%;
209
211
  flex-direction: column;
210
- margin-right: auto;
211
- margin-left: auto;
212
+ ${css$1`
213
+ box-sizing: border-box;
214
+ width: 100%;
215
+ margin-right: auto;
216
+ margin-left: auto;
217
+ `}
212
218
 
213
219
  ${makeItResponsive({
214
220
  key: "$coolgrid",
@@ -228,7 +234,7 @@ var styled_default$1 = styled$1(component$1)`
228
234
  */
229
235
  const DEV_PROPS$1 = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "container" } : {};
230
236
  const Component$1 = ({ children, component, css, width, ...props }) => {
231
- const { containerWidth = {}, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
237
+ const { containerWidth, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
232
238
  const context = useMemo(() => ({
233
239
  columns,
234
240
  size,
@@ -289,8 +295,8 @@ const spacingStyles = ({ gap, gutter }, { rootSize }) => {
289
295
  const getValue = (param) => value(param, rootSize);
290
296
  const spacingX = g / 2 * -1;
291
297
  return css`
292
- margin: ${getValue(isNumber(gutter) ? gutter - g / 2 : g / 2)} ${getValue(spacingX)};
293
- `;
298
+ margin: ${getValue(isNumber(gutter) ? gutter - g / 2 : g / 2)} ${getValue(spacingX)};
299
+ `;
294
300
  };
295
301
  /** Maps the contentAlignX prop to a CSS justify-content value. */
296
302
  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
 
@@ -49,11 +49,13 @@ const getGridContext = (props = {}, theme = {}) => ({
49
49
  });
50
50
  const useGridContext = (props) => {
51
51
  const { theme } = useContext(context);
52
- const ctxProps = pickThemeProps(props, CONTEXT_KEYS);
53
- return {
54
- ...getGridContext(ctxProps, theme),
55
- ...ctxProps
56
- };
52
+ return useMemo(() => {
53
+ const ctxProps = pickThemeProps(props, CONTEXT_KEYS);
54
+ return {
55
+ ...getGridContext(ctxProps, theme),
56
+ ...ctxProps
57
+ };
58
+ }, [props, theme]);
57
59
  };
58
60
 
59
61
  //#endregion
@@ -83,13 +85,15 @@ const widthStyles = ({ size, columns, gap, RNparentWidth }, { rootSize }) => {
83
85
  const s = size;
84
86
  const c = columns;
85
87
  const g = gap;
88
+ if (!RNparentWidth) return "";
86
89
  const width = RNparentWidth / c * s;
87
- const val = hasValue(gap) ? width - g : width;
88
90
  return css$2`
89
91
  flex-grow: 0;
90
92
  flex-shrink: 0;
91
- max-width: ${value(val, rootSize)};
92
- flex-basis: ${value(val, rootSize)};
93
+ ${css$2`
94
+ width: ${value(hasValue(gap) ? Math.max(0, width - g) : width, rootSize)};
95
+ flex-basis: auto;
96
+ `}
93
97
  `;
94
98
  };
95
99
  /** Applies half of the given value as either margin or padding (used for gap and padding distribution). */
@@ -107,7 +111,7 @@ const spacingStyles$1 = (type, param, rootSize) => {
107
111
  const styles$2 = ({ theme, css, rootSize }) => {
108
112
  const { size, columns, gap, padding, extraStyles, RNparentWidth } = theme;
109
113
  if (isVisible(size)) return css`
110
- left: initial;
114
+ ${""}
111
115
  position: relative;
112
116
  ${widthStyles({
113
117
  size,
@@ -121,20 +125,19 @@ const styles$2 = ({ theme, css, rootSize }) => {
121
125
  `;
122
126
  return css`
123
127
  left: -9999px;
124
- position: fixed;
128
+ position: ${"absolute"};
125
129
  margin: 0;
126
130
  padding: 0;
127
131
  `;
128
132
  };
129
133
  var styled_default$2 = styled$2(component$2)`
130
- ${false};
134
+ ${false}
131
135
 
132
136
  position: relative;
133
137
  display: flex;
134
138
  flex-basis: 0;
135
139
  flex-grow: 1;
136
140
  flex-direction: column;
137
- justify-content: stretch;
138
141
 
139
142
  ${makeItResponsive({
140
143
  key: "$coolgrid",
@@ -145,29 +148,32 @@ var styled_default$2 = styled$2(component$2)`
145
148
  `;
146
149
 
147
150
  //#endregion
148
- //#region src/Col/component.tsx
151
+ //#region src/Col/component.native.tsx
149
152
  /**
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.
153
+ * Native Col component that reads RNparentWidth from RowContext
154
+ * and passes it into the styled component so column widths can be
155
+ * computed as absolute pixels (CSS calc() is unavailable on RN).
153
156
  */
154
- const DEV_PROPS$2 = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "col" } : {};
155
157
  const Component$2 = ({ children, component, css, ...props }) => {
158
+ const parentCtx = useContext(RowContext_default);
156
159
  const { colCss, colComponent, columns, gap, size, padding } = useGridContext({
157
- ...useContext(RowContext_default),
160
+ ...parentCtx,
158
161
  ...props
159
162
  });
163
+ const RNparentWidth = parentCtx.RNparentWidth ?? 0;
160
164
  const finalProps = useMemo(() => ({ $coolgrid: {
161
165
  columns,
162
166
  gap,
163
167
  size,
164
168
  padding,
169
+ RNparentWidth,
165
170
  extraStyles: css ?? colCss
166
171
  } }), [
167
172
  columns,
168
173
  gap,
169
174
  size,
170
175
  padding,
176
+ RNparentWidth,
171
177
  css,
172
178
  colCss
173
179
  ]);
@@ -175,7 +181,6 @@ const Component$2 = ({ children, component, css, ...props }) => {
175
181
  ...omitCtxKeys(props),
176
182
  as: component ?? colComponent,
177
183
  ...finalProps,
178
- ...DEV_PROPS$2,
179
184
  children
180
185
  });
181
186
  };
@@ -192,19 +197,18 @@ var Col_default = Component$2;
192
197
  //#region src/Container/styled.ts
193
198
  const { styled: styled$1, css: css$1, component: component$1 } = config;
194
199
  /** 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
- `;
200
+ const styles$1 = ({ theme: t, css, rootSize }) => {
201
+ const w = t.width != null && typeof t.width !== "object" ? t.width : null;
202
+ return css`
203
+ ${w != null ? `max-width: ${value(w, rootSize)};` : ""};
204
+ ${extendCss(t.extraStyles)};
205
+ `;
206
+ };
199
207
  /** Styled Container element. Centered via auto margins with responsive max-width. */
200
208
  var styled_default$1 = styled$1(component$1)`
201
- ${false};
202
-
203
209
  display: flex;
204
- width: 100%;
205
210
  flex-direction: column;
206
- margin-right: auto;
207
- margin-left: auto;
211
+ ${false}
208
212
 
209
213
  ${makeItResponsive({
210
214
  key: "$coolgrid",
@@ -222,9 +226,9 @@ var styled_default$1 = styled$1(component$1)`
222
226
  * components via ContainerContext, and renders a styled wrapper with
223
227
  * responsive max-width.
224
228
  */
225
- const DEV_PROPS$1 = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "container" } : {};
229
+ const DEV_PROPS = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "container" } : {};
226
230
  const Component$1 = ({ children, component, css, width, ...props }) => {
227
- const { containerWidth = {}, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
231
+ const { containerWidth, columns, size, gap, padding, gutter, colCss, colComponent, rowCss, rowComponent, contentAlignX } = useGridContext(props);
228
232
  const context = useMemo(() => ({
229
233
  columns,
230
234
  size,
@@ -260,7 +264,7 @@ const Component$1 = ({ children, component, css, width, ...props }) => {
260
264
  ...omitCtxKeys(props),
261
265
  as: component,
262
266
  ...finalProps,
263
- ...DEV_PROPS$1,
267
+ ...DEV_PROPS,
264
268
  children: /* @__PURE__ */ jsx(ContainerContext_default.Provider, {
265
269
  value: context,
266
270
  children
@@ -284,9 +288,13 @@ const spacingStyles = ({ gap, gutter }, { rootSize }) => {
284
288
  const g = gap;
285
289
  const getValue = (param) => value(param, rootSize);
286
290
  const spacingX = g / 2 * -1;
291
+ const spacingY = isNumber(gutter) ? gutter - g / 2 : g / 2;
287
292
  return css`
288
- margin: ${getValue(isNumber(gutter) ? gutter - g / 2 : g / 2)} ${getValue(spacingX)};
289
- `;
293
+ margin-top: ${getValue(spacingY)};
294
+ margin-bottom: ${getValue(spacingY)};
295
+ margin-left: ${getValue(spacingX)};
296
+ margin-right: ${getValue(spacingX)};
297
+ `;
290
298
  };
291
299
  /** Maps the contentAlignX prop to a CSS justify-content value. */
292
300
  const contentAlign = (align) => {
@@ -324,17 +332,17 @@ var styled_default = styled(component)`
324
332
  `;
325
333
 
326
334
  //#endregion
327
- //#region src/Row/component.tsx
335
+ //#region src/Row/component.native.tsx
328
336
  /**
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.
337
+ * Native Row component that measures its own width via onLayout and passes
338
+ * it as RNparentWidth through RowContext so Col children can compute
339
+ * absolute pixel widths (CSS calc() is unavailable on React Native).
333
340
  */
334
- const DEV_PROPS = process.env.NODE_ENV !== "production" ? { "data-coolgrid": "row" } : {};
335
341
  const Component = ({ children, component, css, contentAlignX: rowAlignX, ...props }) => {
342
+ const parentCtx = useContext(ContainerContext_default);
343
+ const [parentWidth, setParentWidth] = useState(0);
336
344
  const { columns, gap, gutter, rowComponent, rowCss, contentAlignX, containerWidth, size, padding, colCss, colComponent } = useGridContext({
337
- ...useContext(ContainerContext_default),
345
+ ...parentCtx,
338
346
  ...props
339
347
  });
340
348
  const context = useMemo(() => ({
@@ -345,7 +353,8 @@ const Component = ({ children, component, css, contentAlignX: rowAlignX, ...prop
345
353
  colComponent,
346
354
  columns,
347
355
  gap,
348
- gutter
356
+ gutter,
357
+ RNparentWidth: parentWidth
349
358
  }), [
350
359
  containerWidth,
351
360
  size,
@@ -354,7 +363,8 @@ const Component = ({ children, component, css, contentAlignX: rowAlignX, ...prop
354
363
  colComponent,
355
364
  columns,
356
365
  gap,
357
- gutter
366
+ gutter,
367
+ parentWidth
358
368
  ]);
359
369
  const finalProps = useMemo(() => ({ $coolgrid: {
360
370
  contentAlignX: rowAlignX || contentAlignX,
@@ -371,11 +381,15 @@ const Component = ({ children, component, css, contentAlignX: rowAlignX, ...prop
371
381
  css,
372
382
  rowCss
373
383
  ]);
384
+ const onLayout = useCallback((e) => {
385
+ const newWidth = e?.nativeEvent?.layout?.width;
386
+ if (newWidth != null) setParentWidth((prev) => prev === newWidth ? prev : newWidth);
387
+ }, []);
374
388
  return /* @__PURE__ */ jsx(styled_default, {
375
389
  ...omitCtxKeys(props),
376
390
  as: component || rowComponent,
377
391
  ...finalProps,
378
- ...DEV_PROPS,
392
+ onLayout,
379
393
  children: /* @__PURE__ */ jsx(RowContext_default.Provider, {
380
394
  value: context,
381
395
  children
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitus-labs/coolgrid",
3
- "version": "2.0.0-alpha.9+f2f47db",
3
+ "version": "2.0.0-beta.1",
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,26 @@
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-beta.1",
66
+ "@vitus-labs/unistyle": "2.0.0-beta.1",
67
+ "react": ">= 19",
68
+ "react-native": ">= 0.76"
65
69
  },
66
- "devDependencies": {
67
- "@vitus-labs/core": "2.0.0-alpha.9+f2f47db",
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.9+f2f47db"
70
+ "peerDependenciesMeta": {
71
+ "react-native": {
72
+ "optional": true
73
+ }
72
74
  },
73
- "gitHead": "f2f47db887d6a846ee5f9e96f290c59cdde4772a"
75
+ "devDependencies": {
76
+ "@vitus-labs/core": "workspace:*",
77
+ "@vitus-labs/tools-rolldown": "2.2.0",
78
+ "@vitus-labs/tools-storybook": "2.2.0",
79
+ "@vitus-labs/tools-typescript": "2.1.0",
80
+ "@vitus-labs/unistyle": "workspace:*",
81
+ "react-native": ">=0.84.1"
82
+ }
74
83
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2023-present Vit Bokisch
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.