react-justified-layout-ts 2.1.5 → 2.2.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.
Files changed (53) hide show
  1. package/.storybook/main.ts +12 -13
  2. package/.storybook/preview.ts +11 -4
  3. package/README.md +44 -44
  4. package/dist/components/JustifiedGrid.js +10 -9
  5. package/dist/components/layout.css +3 -3
  6. package/dist/src/components/JustifiedGrid.d.ts +13 -0
  7. package/dist/src/components/JustifiedGrid.js +59 -0
  8. package/dist/src/components/TSJustifiedLayout.d.ts +18 -0
  9. package/dist/src/components/TSJustifiedLayout.js +99 -0
  10. package/dist/src/index.d.ts +2 -0
  11. package/dist/src/index.js +7 -0
  12. package/dist/src/stories/ConfiguredJustifiedLayout.d.ts +3 -0
  13. package/dist/src/stories/ConfiguredJustifiedLayout.js +12 -0
  14. package/dist/src/stories/JustifiedLayout.stories.d.ts +13 -0
  15. package/dist/src/stories/JustifiedLayout.stories.js +202 -0
  16. package/dist/stories/JustifiedLayout.stories.d.ts +0 -1
  17. package/dist/stories/JustifiedLayout.stories.js +5 -6
  18. package/package.json +43 -49
  19. package/src/components/JustifiedGrid.d.ts +14 -0
  20. package/src/components/JustifiedGrid.d.ts.map +1 -0
  21. package/src/components/JustifiedGrid.js +63 -0
  22. package/src/components/JustifiedGrid.js.map +1 -0
  23. package/src/components/JustifiedGrid.tsx +79 -78
  24. package/src/components/TSJustifiedLayout.d.ts +19 -0
  25. package/src/components/TSJustifiedLayout.d.ts.map +1 -0
  26. package/src/components/TSJustifiedLayout.js +98 -0
  27. package/src/components/TSJustifiedLayout.js.map +1 -0
  28. package/src/components/TSJustifiedLayout.tsx +139 -139
  29. package/src/components/layout.css +3 -3
  30. package/src/declarations.d.ts +1 -0
  31. package/src/index.d.ts +4 -0
  32. package/src/index.d.ts.map +1 -0
  33. package/src/index.js +8 -0
  34. package/src/index.js.map +1 -0
  35. package/src/index.ts +3 -2
  36. package/src/stories/Configure.mdx +388 -364
  37. package/src/stories/ConfiguredJustifiedLayout.d.ts +3 -0
  38. package/src/stories/ConfiguredJustifiedLayout.d.ts.map +1 -0
  39. package/src/stories/ConfiguredJustifiedLayout.js +10 -0
  40. package/src/stories/ConfiguredJustifiedLayout.js.map +1 -0
  41. package/src/stories/ConfiguredJustifiedLayout.tsx +22 -22
  42. package/src/stories/JustifiedLayout.stories.d.ts +13 -0
  43. package/src/stories/JustifiedLayout.stories.d.ts.map +1 -0
  44. package/src/stories/JustifiedLayout.stories.js +197 -0
  45. package/src/stories/JustifiedLayout.stories.js.map +1 -0
  46. package/src/stories/JustifiedLayout.stories.tsx +204 -205
  47. package/src/stories/assets/accessibility.svg +1 -5
  48. package/src/stories/assets/discord.svg +1 -15
  49. package/src/stories/assets/github.svg +1 -3
  50. package/src/stories/assets/tutorials.svg +1 -12
  51. package/src/stories/assets/youtube.svg +1 -4
  52. package/tsconfig.json +44 -15
  53. package/LICENSE +0 -21
@@ -7,7 +7,6 @@ exports.SingleWithDiv = exports.Single = exports.Divs = exports.Secondary = expo
7
7
  const ConfiguredJustifiedLayout_1 = require("./ConfiguredJustifiedLayout");
8
8
  const react_1 = __importDefault(require("react"));
9
9
  const react_loading_skeleton_1 = __importDefault(require("react-loading-skeleton"));
10
- require("react-loading-skeleton/dist/skeleton.css");
11
10
  const meta = {
12
11
  title: 'JustifiedLayout/Basic',
13
12
  component: ConfiguredJustifiedLayout_1.ConfiguredJustifiedLayout,
@@ -132,7 +131,7 @@ const displayedImages = [
132
131
  exports.Primary = {
133
132
  name: "Complex Elements",
134
133
  args: {
135
- width: 491,
134
+ width: 1920,
136
135
  showWidows: true,
137
136
  targetRowHeight: undefined,
138
137
  rowSpacing: undefined,
@@ -151,7 +150,7 @@ exports.Primary = {
151
150
  exports.Secondary = {
152
151
  name: "Image Tag Elements",
153
152
  args: {
154
- width: 847,
153
+ width: 1920,
155
154
  showWidows: true,
156
155
  targetRowHeight: undefined,
157
156
  rowSpacing: undefined,
@@ -164,7 +163,7 @@ exports.Secondary = {
164
163
  exports.Divs = {
165
164
  name: "Divs Only",
166
165
  args: {
167
- width: 847,
166
+ width: 1920,
168
167
  showWidows: true,
169
168
  targetRowHeight: undefined,
170
169
  rowSpacing: undefined,
@@ -178,7 +177,7 @@ exports.Single = {
178
177
  name: "Single Elements",
179
178
  args: {
180
179
  children: [react_1.default.createElement("img", { src: 'https://alcorsiteartbucket.s3.amazonaws.com/webp/alcor_wow.webp' })],
181
- width: 847,
180
+ width: 1920,
182
181
  showWidows: true,
183
182
  targetRowHeight: undefined,
184
183
  rowSpacing: undefined,
@@ -192,7 +191,7 @@ exports.SingleWithDiv = {
192
191
  args: {
193
192
  children: [react_1.default.createElement("div", null,
194
193
  react_1.default.createElement("img", { src: 'https://alcorsiteartbucket.s3.amazonaws.com/webp/alcor_wow.webp' }))],
195
- width: 847,
194
+ width: 1920,
196
195
  showWidows: true,
197
196
  targetRowHeight: undefined,
198
197
  rowSpacing: undefined,
package/package.json CHANGED
@@ -1,49 +1,43 @@
1
- {
2
- "name": "react-justified-layout-ts",
3
- "version": "2.1.5",
4
- "description": "A component based off Flickr's justified layout that is compatible with Typescript",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
- "scripts": {
8
- "test": "echo \"Error: no test specified\" && exit 1",
9
- "typescript": "tsc && copyfiles -u 1 src/**/*.css dist/",
10
- "storybook": "storybook dev -p 6006",
11
- "build-storybook": "storybook build"
12
- },
13
- "keywords": [],
14
- "author": "Alan19",
15
- "license": "MIT",
16
- "dependencies": {
17
- "@types/node": "^24.0.3",
18
- "lodash": "^4.17.21",
19
- "react-use": "^17.6.0",
20
- "react-use-measure": "^2.1.7"
21
- },
22
- "devDependencies": {
23
- "@chromatic-com/storybook": "^3.2.7",
24
- "@storybook/addon-essentials": "^8.6.14",
25
- "@storybook/addon-interactions": "^8.6.14",
26
- "@storybook/addon-links": "^8.6.14",
27
- "@storybook/addon-onboarding": "^8.6.14",
28
- "@storybook/addon-webpack5-compiler-swc": "^3.0.0",
29
- "@storybook/blocks": "^8.6.14",
30
- "@storybook/react": "^8.6.14",
31
- "@storybook/react-webpack5": "^8.6.14",
32
- "@storybook/test": "^8.6.14",
33
- "@types/lodash": "^4.17.18",
34
- "@types/react": "^19.1.8",
35
- "copyfiles": "^2.4.1",
36
- "react": "^19.1.0",
37
- "react-loading-skeleton": "^3.5.0",
38
- "rimraf": "^6.0.1",
39
- "storybook": "^8.6.14",
40
- "typescript": "^5.8.3"
41
- },
42
- "peerDependencies": {
43
- "react": "^18.2.0"
44
- },
45
- "repository": {
46
- "type": "git",
47
- "url": "git+https://github.com/Alan19/react-justified-layout-ts.git"
48
- }
49
- }
1
+ {
2
+ "name": "react-justified-layout-ts",
3
+ "version": "2.2.1",
4
+ "description": "A component based off Flickr's justified layout that is compatible with Typescript",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "scripts": {
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "typescript": "tsc && copyfiles -u 1 src/**/*.css dist/",
10
+ "storybook": "storybook dev -p 6006",
11
+ "build-storybook": "storybook build"
12
+ },
13
+ "keywords": [],
14
+ "author": "Alan19",
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "@types/node": "^25.5.2",
18
+ "lodash": "^4.18.1",
19
+ "react-use": "^17.6.0",
20
+ "react-use-measure": "^2.1.7"
21
+ },
22
+ "devDependencies": {
23
+ "copyfiles": "^2.4.1",
24
+ "react": "^19.2.4",
25
+ "react-loading-skeleton": "^3.5.0",
26
+ "rimraf": "^6.1.3",
27
+ "typescript": "^6.0.2",
28
+ "storybook": "^10.3.4",
29
+ "@storybook/react-vite": "^10.3.4",
30
+ "@chromatic-com/storybook": "^5.1.1",
31
+ "@storybook/addon-vitest": "^10.3.4",
32
+ "@storybook/addon-a11y": "^10.3.4",
33
+ "@storybook/addon-docs": "^10.3.4",
34
+ "@storybook/addon-onboarding": "^10.3.4",
35
+ "vitest": "4.1.2",
36
+ "playwright": "^1.59.1",
37
+ "@vitest/browser-playwright": "4.1.2"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/Alan19/react-justified-layout-ts.git"
42
+ }
43
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import './layout.css';
3
+ export interface JustifiedGridProps {
4
+ aspectRatioList: number[];
5
+ itemSpacing?: number;
6
+ rowSpacing?: number;
7
+ targetRowHeight?: number;
8
+ targetRowHeightTolerance?: number;
9
+ width: number;
10
+ children: React.JSX.Element[];
11
+ containerStyle?: React.CSSProperties;
12
+ }
13
+ export declare function JustifiedGrid(props: Readonly<JustifiedGridProps>): import("react/jsx-runtime").JSX.Element;
14
+ //# sourceMappingURL=JustifiedGrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JustifiedGrid.d.ts","sourceRoot":"","sources":["JustifiedGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,cAAc,CAAA;AAErB,MAAM,WAAW,kBAAkB;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC9B,cAAc,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CACxC;AAoCD,wBAAgB,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,kBAAkB,CAAC,2CA8BhE"}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.JustifiedGrid = JustifiedGrid;
7
+ const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const lodash_1 = __importDefault(require("lodash"));
9
+ require("./layout.css");
10
+ function getJustifiedGridRowConfiguration(width, targetRowHeightTolerance, aspectRatioList, targetRowHeight, itemSpacing) {
11
+ let buffer = [];
12
+ const rows = [];
13
+ // We assume that the row will have the specified height, which allows us to convert aspect ratios into widths
14
+ const minRowWidth = width * (1 / (1 + targetRowHeightTolerance));
15
+ const maxRowWidth = width * (1 / (1 - targetRowHeightTolerance));
16
+ aspectRatioList.forEach((aspectRatio, index) => {
17
+ let currentRowWidth = (lodash_1.default.sum(buffer) * targetRowHeight + aspectRatio * targetRowHeight + itemSpacing * (buffer.length));
18
+ // If the new item's width would cause it to fall between the tolerances for max widths, finish the row
19
+ // If the new item's width would cause it to exceed the tolerances for the row, add it to a new row
20
+ if (buffer.length === 0 || currentRowWidth < maxRowWidth) {
21
+ buffer.push(aspectRatio);
22
+ if (currentRowWidth > minRowWidth) {
23
+ rows.push(buffer);
24
+ buffer = [];
25
+ }
26
+ // If we're handling the last item, and it doesn't exceed the minimum tolerance for the row width, we add a "dummy" item to make the rest of the row now take up the whole width
27
+ else if (index === aspectRatioList.length - 1) {
28
+ buffer.push((width - lodash_1.default.sum(buffer) * targetRowHeight - itemSpacing * (buffer.length - 1)) / targetRowHeight);
29
+ }
30
+ }
31
+ else {
32
+ rows.push(buffer);
33
+ buffer = [aspectRatio];
34
+ }
35
+ });
36
+ if (buffer.length !== 0) {
37
+ rows.push(buffer);
38
+ }
39
+ return rows;
40
+ }
41
+ function JustifiedGrid(props) {
42
+ const { targetRowHeightTolerance = .25, width, targetRowHeight = 320, itemSpacing = 8, rowSpacing = 8, children, containerStyle, aspectRatioList } = props;
43
+ const rows = getJustifiedGridRowConfiguration(width, targetRowHeightTolerance, aspectRatioList, targetRowHeight, itemSpacing);
44
+ let childNodeCounter = -1;
45
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
46
+ display: 'flex',
47
+ flexDirection: 'column',
48
+ gap: rowSpacing
49
+ }, children: rows.map((value) => {
50
+ return (0, jsx_runtime_1.jsx)("div", { className: 'justified-row', style: {
51
+ display: "flex",
52
+ flexDirection: "row",
53
+ gap: itemSpacing,
54
+ }, children: value.map((aspectRatio) => {
55
+ childNodeCounter++;
56
+ return (0, jsx_runtime_1.jsx)("div", { style: {
57
+ flex: value.length === 1 ? 1 : aspectRatio,
58
+ ...containerStyle
59
+ }, children: children[childNodeCounter] });
60
+ }) });
61
+ }) }));
62
+ }
63
+ //# sourceMappingURL=JustifiedGrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JustifiedGrid.js","sourceRoot":"","sources":["JustifiedGrid.tsx"],"names":[],"mappings":"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"}
@@ -1,79 +1,80 @@
1
- import React from "react";
2
- import _ from "lodash";
3
- import './layout.css'
4
-
5
- export interface JustifiedGridProps {
6
- aspectRatioList: number[];
7
- itemSpacing?: number;
8
- rowSpacing?: number;
9
- targetRowHeight?: number;
10
- targetRowHeightTolerance?: number;
11
- width: number;
12
- children: React.JSX.Element[];
13
- containerStyle?: React.CSSProperties;
14
- }
15
-
16
- function getJustifiedGridRowConfiguration(width: number, targetRowHeightTolerance: number, aspectRatioList: number[], targetRowHeight: number, itemSpacing: number): number[][] {
17
- let buffer: number[] = []
18
- const rows: number[][] = []
19
-
20
- // We assume that the row will have the specified height, which allows us to convert aspect ratios into widths
21
- const minRowWidth = width * (1 / (1 + targetRowHeightTolerance));
22
- const maxRowWidth = width * (1 / (1 - targetRowHeightTolerance));
23
- aspectRatioList.forEach((aspectRatio, index) => {
24
- let currentRowWidth = (_.sum(buffer) * targetRowHeight + aspectRatio * targetRowHeight + itemSpacing * (buffer.length));
25
- // If the new item's width would cause it to fall between the tolerances for max widths, finish the row
26
- // If the new item's width would cause it to exceed the tolerances for the row, add it to a new row
27
- if (buffer.length === 0 || currentRowWidth < maxRowWidth) {
28
- buffer.push(aspectRatio);
29
- if (currentRowWidth > minRowWidth) {
30
- rows.push(buffer)
31
- buffer = []
32
- }
33
- // If we're handling the last item, and it doesn't exceed the minimum tolerance for the row width, we add a "dummy" item to make the rest of the row now take up the whole width
34
- else if (index === aspectRatioList.length - 1) {
35
- buffer.push((width - _.sum(buffer) * targetRowHeight - itemSpacing * (buffer.length - 1)) / targetRowHeight);
36
- }
37
- }
38
- else {
39
- rows.push(buffer)
40
- buffer = [aspectRatio];
41
- }
42
- })
43
-
44
- if (buffer.length !== 0) {
45
- rows.push(buffer)
46
- }
47
- return rows;
48
- }
49
-
50
- export function JustifiedGrid(props: Readonly<JustifiedGridProps>) {
51
- const {targetRowHeightTolerance = .25, width, targetRowHeight = 320, itemSpacing = 8, rowSpacing = 8, children, containerStyle, aspectRatioList} = props;
52
- const rows = getJustifiedGridRowConfiguration(width, targetRowHeightTolerance, aspectRatioList, targetRowHeight, itemSpacing);
53
-
54
- let childNodeCounter = -1;
55
-
56
- function renderRowItem(value: number[], aspectRatio: number) {
57
- childNodeCounter++;
58
- return <div style={{flex: value.length === 1 ? 1 : aspectRatio, ...containerStyle}}>
59
- {children[childNodeCounter]}
60
- </div>;
61
- }
62
-
63
- return (
64
- <div style={{
65
- display: 'flex',
66
- flexDirection: 'column',
67
- gap: rowSpacing
68
- }}>
69
- {rows.map(value =>
70
- <div className={'justified-row'} style={{
71
- display: "flex",
72
- flexDirection: "row",
73
- gap: itemSpacing,
74
- }}>
75
- {value.map(aspectRatio => renderRowItem(value, aspectRatio))}
76
- </div>)}
77
- </div>
78
- );
1
+ import React from "react";
2
+ import _ from "lodash";
3
+ import './layout.css'
4
+
5
+ export interface JustifiedGridProps {
6
+ aspectRatioList: number[];
7
+ itemSpacing?: number;
8
+ rowSpacing?: number;
9
+ targetRowHeight?: number;
10
+ targetRowHeightTolerance?: number;
11
+ width: number;
12
+ children: React.JSX.Element[];
13
+ containerStyle?: React.CSSProperties;
14
+ }
15
+
16
+ function getJustifiedGridRowConfiguration(width: number, targetRowHeightTolerance: number, aspectRatioList: number[], targetRowHeight: number, itemSpacing: number): number[][] {
17
+ let buffer: number[] = []
18
+ const rows: number[][] = []
19
+
20
+ // We assume that the row will have the specified height, which allows us to convert aspect ratios into widths
21
+ const minRowWidth = width * (1 / (1 + targetRowHeightTolerance));
22
+ const maxRowWidth = width * (1 / (1 - targetRowHeightTolerance));
23
+ aspectRatioList.forEach((aspectRatio, index) => {
24
+ let currentRowWidth = (_.sum(buffer) * targetRowHeight + aspectRatio * targetRowHeight + itemSpacing * (buffer.length));
25
+ // If the new item's width would cause it to fall between the tolerances for max widths, finish the row
26
+ // If the new item's width would cause it to exceed the tolerances for the row, add it to a new row
27
+ if (buffer.length === 0 || currentRowWidth < maxRowWidth) {
28
+ buffer.push(aspectRatio);
29
+ if (currentRowWidth > minRowWidth) {
30
+ rows.push(buffer)
31
+ buffer = []
32
+ }
33
+ // If we're handling the last item, and it doesn't exceed the minimum tolerance for the row width, we add a "dummy" item to make the rest of the row now take up the whole width
34
+ else if (index === aspectRatioList.length - 1) {
35
+ buffer.push((width - _.sum(buffer) * targetRowHeight - itemSpacing * (buffer.length - 1)) / targetRowHeight);
36
+ }
37
+ }
38
+ else {
39
+ rows.push(buffer)
40
+ buffer = [aspectRatio];
41
+ }
42
+ })
43
+
44
+ if (buffer.length !== 0) {
45
+ rows.push(buffer)
46
+ }
47
+ return rows;
48
+ }
49
+
50
+ export function JustifiedGrid(props: Readonly<JustifiedGridProps>) {
51
+ const {targetRowHeightTolerance = .25, width, targetRowHeight = 320, itemSpacing = 8, rowSpacing = 8, children, containerStyle, aspectRatioList} = props;
52
+ const rows = getJustifiedGridRowConfiguration(width, targetRowHeightTolerance, aspectRatioList, targetRowHeight, itemSpacing);
53
+
54
+ let childNodeCounter = -1;
55
+ return (
56
+ <div style={{
57
+ display: 'flex',
58
+ flexDirection: 'column',
59
+ gap: rowSpacing
60
+ }}>
61
+ {rows.map((value) => {
62
+ return <div className={'justified-row'} style={{
63
+ display: "flex",
64
+ flexDirection: "row",
65
+ gap: itemSpacing,
66
+ }}>
67
+ {value.map((aspectRatio) => {
68
+ childNodeCounter++;
69
+ return <div style={{
70
+ flex: value.length === 1 ? 1 : aspectRatio,
71
+ ...containerStyle
72
+ }}>
73
+ {children[childNodeCounter]}
74
+ </div>;
75
+ })}
76
+ </div>
77
+ })}
78
+ </div>
79
+ );
79
80
  }
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ import './layout.css';
3
+ export interface TSJustifiedLayoutProps {
4
+ aspectRatioList: number[];
5
+ itemSpacing?: number;
6
+ rowSpacing?: number;
7
+ targetRowHeight?: number;
8
+ targetRowHeightTolerance?: number;
9
+ width: number;
10
+ children: React.JSX.Element[];
11
+ showWidows?: boolean;
12
+ containerStyle?: React.CSSProperties;
13
+ }
14
+ /**
15
+ * @deprecated Use the new {@link JustifiedGrid} component instead as it has better handling for heights of widow rows and future work will be done there
16
+ */
17
+ declare function TSJustifiedLayout({ children, aspectRatioList, itemSpacing, rowSpacing, showWidows, targetRowHeight, targetRowHeightTolerance, width, containerStyle }: Readonly<TSJustifiedLayoutProps>): import("react/jsx-runtime").JSX.Element;
18
+ export { TSJustifiedLayout, TSJustifiedLayout as JustifiedGrid };
19
+ //# sourceMappingURL=TSJustifiedLayout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TSJustifiedLayout.d.ts","sourceRoot":"","sources":["TSJustifiedLayout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,cAAc,CAAA;AAIrB,MAAM,WAAW,sBAAsB;IACnC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAKxC;AAED;;GAEG;AACH,iBAAS,iBAAiB,CAAC,EACI,QAAQ,EACR,eAAe,EACf,WAAgB,EAChB,UAAe,EACf,UAAiB,EACjB,eAAqB,EACrB,wBAA8B,EAC9B,KAAK,EACL,cAAc,EACjB,EAAE,QAAQ,CAAC,sBAAsB,CAAC,2CAuG7D;AAED,OAAO,EAAC,iBAAiB,EAAE,iBAAiB,IAAI,aAAa,EAAC,CAAA"}
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TSJustifiedLayout = TSJustifiedLayout;
4
+ exports.JustifiedGrid = TSJustifiedLayout;
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ require("./layout.css");
7
+ /**
8
+ * @deprecated Use the new {@link JustifiedGrid} component instead as it has better handling for heights of widow rows and future work will be done there
9
+ */
10
+ function TSJustifiedLayout({ children, aspectRatioList, itemSpacing = 10, rowSpacing = 10, showWidows = true, targetRowHeight = 320, targetRowHeightTolerance = .25, width, containerStyle }) {
11
+ const minAspectRatio = width / targetRowHeight * (1 - targetRowHeightTolerance);
12
+ const maxAspectRatio = width / targetRowHeight * (1 + targetRowHeightTolerance);
13
+ const rows = [];
14
+ let rowBuffer = [];
15
+ /**
16
+ * Attempts to add an item to the current row buffer
17
+ * @param value The new aspect ratio to be checked
18
+ * @return If the buffer can accept the new value
19
+ * */
20
+ function addItem(value) {
21
+ const newItems = rowBuffer.concat(value);
22
+ const newAspectRatio = newItems.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
23
+ const rowWidthMinusSpacing = width - (newItems.length - 1) * itemSpacing;
24
+ const targetAspectRatio = rowWidthMinusSpacing / targetRowHeight;
25
+ // Row still has space
26
+ if (newAspectRatio < minAspectRatio) {
27
+ rowBuffer.push(value);
28
+ }
29
+ // Row ran out of space, and the new item is larger than the max aspect ratio for the row
30
+ else if (newAspectRatio > maxAspectRatio) {
31
+ // Always accept if it's just 1 item
32
+ if (rowBuffer.length === 0) {
33
+ rowBuffer.push(value);
34
+ rows.push({ items: rowBuffer, height: rowWidthMinusSpacing / newAspectRatio });
35
+ rowBuffer = [];
36
+ }
37
+ else {
38
+ // Calculate width/aspect ratio for row before adding new item
39
+ const previousRowWidthWithoutSpacing = width - (rowBuffer.length - 1) * itemSpacing;
40
+ const previousAspectRatio = rowBuffer.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
41
+ const previousTargetAspectRatio = previousRowWidthWithoutSpacing / targetRowHeight;
42
+ // If the new aspect ratio is farther from the target after the insert, then push row buffer and insert new item into the next row
43
+ if (Math.abs(newAspectRatio - targetAspectRatio) > Math.abs(previousAspectRatio - previousTargetAspectRatio)) {
44
+ rows.push({ items: rowBuffer, height: previousRowWidthWithoutSpacing / previousAspectRatio });
45
+ rowBuffer = [value];
46
+ }
47
+ // If the new aspect ratio is closer to the target aspect ratio, then insert item and push row buffer
48
+ else {
49
+ rowBuffer.push(value);
50
+ rows.push({ items: rowBuffer, height: rowWidthMinusSpacing / newAspectRatio });
51
+ rowBuffer = [];
52
+ }
53
+ }
54
+ }
55
+ else {
56
+ // New aspect ratio is within aspect ratio tolerance, so we finish off the row
57
+ rowBuffer.push(value);
58
+ rows.push({ items: rowBuffer, height: rowWidthMinusSpacing / newAspectRatio });
59
+ rowBuffer = [];
60
+ }
61
+ }
62
+ aspectRatioList.forEach((value) => {
63
+ addItem(value);
64
+ });
65
+ // Handle leftover content
66
+ if (showWidows && rowBuffer.length !== 0) {
67
+ rows.push({ items: rowBuffer, height: rows.length === 0 ? targetRowHeight : rows.at(-1)?.height });
68
+ }
69
+ let childNodeCounter = -1;
70
+ /**
71
+ * Clone the children element, and inject the height of the element as a prop
72
+ */
73
+ function renderRowItem(aspectRatio, isSoloRow, lastRowWithinTolerance, fakeElementAspectRatio) {
74
+ childNodeCounter++;
75
+ return (0, jsx_runtime_1.jsxs)("div", { style: {
76
+ flex: isSoloRow ? 1 : aspectRatio,
77
+ ...containerStyle
78
+ }, children: [children[childNodeCounter], lastRowWithinTolerance && (0, jsx_runtime_1.jsx)("div", { style: { flex: fakeElementAspectRatio } })] });
79
+ }
80
+ // TODO Figure out how to eliminate the tiny gap between div and actual image height
81
+ // TODO Make bottom row respect length restrictions
82
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
83
+ display: 'flex',
84
+ flexDirection: 'column',
85
+ gap: rowSpacing
86
+ }, children: rows.map((value, index, array) => {
87
+ let isLastRow = index === array.length - 1 && showWidows;
88
+ let rowAspectRatioSum = value.items.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
89
+ const isLastRowWithinTolerance = isLastRow && rowAspectRatioSum * value.height + (value.items.length - 1) * itemSpacing < minAspectRatio * value.height;
90
+ const fakeElementAspectRatio = (width - rowAspectRatioSum * value.height - (value.items.length - 1) * itemSpacing) / value.height;
91
+ return (0, jsx_runtime_1.jsx)("div", { className: 'justified-row', style: {
92
+ display: "flex",
93
+ flexDirection: "row",
94
+ gap: itemSpacing,
95
+ }, children: value.items.map((aspectRatio) => renderRowItem(aspectRatio, value.items.length === 1, isLastRowWithinTolerance, fakeElementAspectRatio)) });
96
+ }) }));
97
+ }
98
+ //# sourceMappingURL=TSJustifiedLayout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TSJustifiedLayout.js","sourceRoot":"","sources":["TSJustifiedLayout.tsx"],"names":[],"mappings":"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"}