@khanacademy/wonder-blocks-layout 1.4.6 → 1.4.9
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/CHANGELOG.md +20 -0
- package/dist/es/index.js +26 -94
- package/package.json +4 -5
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +5 -5
- package/src/components/__tests__/media-layout-context.test.js +1 -0
- package/src/components/__tests__/media-layout.test.js +1 -0
- package/src/components/spring.stories.js +4 -4
- package/src/components/strut.stories.js +4 -4
- package/LICENSE +0 -21
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @khanacademy/wonder-blocks-layout
|
|
2
|
+
|
|
3
|
+
## 1.4.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @khanacademy/wonder-blocks-core@4.3.1
|
|
8
|
+
|
|
9
|
+
## 1.4.8
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [246a921d]
|
|
14
|
+
- @khanacademy/wonder-blocks-core@4.3.0
|
|
15
|
+
|
|
16
|
+
## 1.4.7
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- @khanacademy/wonder-blocks-core@4.2.1
|
package/dist/es/index.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import _extends from '@babel/runtime/helpers/extends';
|
|
2
|
-
import
|
|
2
|
+
import * as React from 'react';
|
|
3
3
|
import Spacing from '@khanacademy/wonder-blocks-spacing';
|
|
4
4
|
import { StyleSheet } from 'aphrodite';
|
|
5
5
|
import { View } from '@khanacademy/wonder-blocks-core';
|
|
6
6
|
|
|
7
|
-
// All possible valid media sizes
|
|
8
7
|
const VALID_MEDIA_SIZES = ["small", "medium", "large"];
|
|
9
|
-
const mediaDefaultSpecLargeMarginWidth = Spacing.large_24;
|
|
10
|
-
// three different settings (roughly mobile, tablet, and desktop).
|
|
11
|
-
|
|
8
|
+
const mediaDefaultSpecLargeMarginWidth = Spacing.large_24;
|
|
12
9
|
const MEDIA_DEFAULT_SPEC = {
|
|
13
10
|
small: {
|
|
14
11
|
query: "(max-width: 767px)",
|
|
@@ -29,8 +26,7 @@ const MEDIA_DEFAULT_SPEC = {
|
|
|
29
26
|
marginWidth: mediaDefaultSpecLargeMarginWidth,
|
|
30
27
|
maxWidth: 1120 + mediaDefaultSpecLargeMarginWidth * 2
|
|
31
28
|
}
|
|
32
|
-
};
|
|
33
|
-
|
|
29
|
+
};
|
|
34
30
|
const MEDIA_INTERNAL_SPEC = {
|
|
35
31
|
large: {
|
|
36
32
|
query: "(min-width: 1px)",
|
|
@@ -38,8 +34,7 @@ const MEDIA_INTERNAL_SPEC = {
|
|
|
38
34
|
gutterWidth: Spacing.xLarge_32,
|
|
39
35
|
marginWidth: Spacing.medium_16
|
|
40
36
|
}
|
|
41
|
-
};
|
|
42
|
-
|
|
37
|
+
};
|
|
43
38
|
const MEDIA_MODAL_SPEC = {
|
|
44
39
|
small: {
|
|
45
40
|
query: "(max-width: 767px)",
|
|
@@ -59,24 +54,13 @@ const defaultContext = {
|
|
|
59
54
|
ssrSize: "large",
|
|
60
55
|
mediaSpec: MEDIA_DEFAULT_SPEC
|
|
61
56
|
};
|
|
62
|
-
var MediaLayoutContext =
|
|
57
|
+
var MediaLayoutContext = React.createContext(defaultContext);
|
|
63
58
|
|
|
64
59
|
const queries = [].concat(Object.values(MEDIA_DEFAULT_SPEC).map(spec => spec.query), Object.values(MEDIA_INTERNAL_SPEC).map(spec => spec.query), Object.values(MEDIA_MODAL_SPEC).map(spec => spec.query));
|
|
65
|
-
const mediaQueryLists = {};
|
|
66
|
-
|
|
67
|
-
// If for some reason we're not able to resolve the current media size we
|
|
68
|
-
// fall back to this state.
|
|
60
|
+
const mediaQueryLists = {};
|
|
69
61
|
const DEFAULT_SIZE = "large";
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
* `MediaLayout` is responsible for changing the rendering of contents at
|
|
73
|
-
* differently sized viewports. `MediaLayoutContext.Provider` can be used
|
|
74
|
-
* to specify different breakpoint configurations. By default it uses
|
|
75
|
-
* `MEDIA_DEFAULT_SPEC`. See media-layout-context.js for additiional options.
|
|
76
|
-
*/
|
|
77
|
-
class MediaLayoutInternal extends Component {
|
|
78
|
-
// A collection of thunks that's used to clean up event listeners
|
|
79
|
-
// when the component is unmounted.
|
|
63
|
+
class MediaLayoutInternal extends React.Component {
|
|
80
64
|
constructor(props) {
|
|
81
65
|
super(props);
|
|
82
66
|
this.state = {
|
|
@@ -86,11 +70,10 @@ class MediaLayoutInternal extends Component {
|
|
|
86
70
|
}
|
|
87
71
|
|
|
88
72
|
componentDidMount() {
|
|
89
|
-
// TODO(WB-534): handle changes to mediaSpec prop
|
|
90
73
|
const entries = Object.entries(this.props.mediaSpec);
|
|
91
74
|
|
|
92
75
|
for (const [size, spec] of entries) {
|
|
93
|
-
const mql = mediaQueryLists[spec.query];
|
|
76
|
+
const mql = mediaQueryLists[spec.query];
|
|
94
77
|
|
|
95
78
|
if (!mql) {
|
|
96
79
|
continue;
|
|
@@ -110,14 +93,10 @@ class MediaLayoutInternal extends Component {
|
|
|
110
93
|
}
|
|
111
94
|
|
|
112
95
|
componentWillUnmount() {
|
|
113
|
-
// Remove our listeners.
|
|
114
96
|
this.cleanupThunks.forEach(cleaup => cleaup());
|
|
115
97
|
}
|
|
116
98
|
|
|
117
99
|
getCurrentSize(spec) {
|
|
118
|
-
// If we have a state with the current size in it then we always want
|
|
119
|
-
// to use that. This will happen if the viewport changes sizes after
|
|
120
|
-
// we've already initialized.
|
|
121
100
|
if (this.state.size) {
|
|
122
101
|
return this.state.size;
|
|
123
102
|
} else {
|
|
@@ -133,48 +112,33 @@ class MediaLayoutInternal extends Component {
|
|
|
133
112
|
}
|
|
134
113
|
|
|
135
114
|
return DEFAULT_SIZE;
|
|
136
|
-
}
|
|
137
|
-
// environment) if there is no window object or matchMedia function
|
|
138
|
-
// available.
|
|
139
|
-
|
|
115
|
+
}
|
|
140
116
|
|
|
141
117
|
isServerSide() {
|
|
142
118
|
return typeof window === "undefined" || !window.matchMedia;
|
|
143
|
-
}
|
|
144
|
-
// We do this by looking at all of the stylesheets specified in the
|
|
145
|
-
// styleSheets prop and then all of the individual styles. We merge the
|
|
146
|
-
// styles together
|
|
147
|
-
// TODO(WB-533): move to util.js to make it easier to test
|
|
148
|
-
|
|
119
|
+
}
|
|
149
120
|
|
|
150
121
|
getMockStyleSheet(mediaSize) {
|
|
151
122
|
const {
|
|
152
123
|
styleSheets
|
|
153
124
|
} = this.props;
|
|
154
|
-
const mockStyleSheet = {};
|
|
125
|
+
const mockStyleSheet = {};
|
|
155
126
|
|
|
156
127
|
if (!styleSheets) {
|
|
157
128
|
return mockStyleSheet;
|
|
158
|
-
}
|
|
159
|
-
|
|
129
|
+
}
|
|
160
130
|
|
|
161
131
|
for (const styleSize of Object.keys(styleSheets)) {
|
|
162
132
|
const styleSheet = styleSheets[styleSize];
|
|
163
133
|
|
|
164
134
|
if (!styleSheet) {
|
|
165
135
|
continue;
|
|
166
|
-
}
|
|
167
|
-
|
|
136
|
+
}
|
|
168
137
|
|
|
169
138
|
for (const name of Object.keys(styleSheet)) {
|
|
170
|
-
if (
|
|
171
|
-
Object.prototype.hasOwnProperty.call(mockStyleSheet, name)) {
|
|
139
|
+
if (Object.prototype.hasOwnProperty.call(mockStyleSheet, name)) {
|
|
172
140
|
continue;
|
|
173
|
-
}
|
|
174
|
-
// the stylesheets together in least-specific to most-specific
|
|
175
|
-
// priority (thus small/medium/large styles will always have
|
|
176
|
-
// precedence over "all" or mdOrSmaller/mdOrLarger/etc.).
|
|
177
|
-
|
|
141
|
+
}
|
|
178
142
|
|
|
179
143
|
mockStyleSheet[name] = [styleSheets.all && styleSheets.all[name], mediaSize === "small" && [styleSheets.mdOrSmaller && styleSheets.mdOrSmaller[name], styleSheets.small && styleSheets.small[name]], mediaSize === "medium" && [styleSheets.mdOrSmaller && styleSheets.mdOrSmaller[name], styleSheets.mdOrLarger && styleSheets.mdOrLarger[name], styleSheets.medium && styleSheets.medium[name]], mediaSize === "large" && [styleSheets.mdOrLarger && styleSheets.mdOrLarger[name], styleSheets.large && styleSheets.large[name]]];
|
|
180
144
|
}
|
|
@@ -189,23 +153,15 @@ class MediaLayoutInternal extends Component {
|
|
|
189
153
|
mediaSpec,
|
|
190
154
|
ssrSize,
|
|
191
155
|
overrideSize
|
|
192
|
-
} = this.props;
|
|
193
|
-
// to query whether any of them match.
|
|
156
|
+
} = this.props;
|
|
194
157
|
|
|
195
158
|
if (!this.isServerSide()) {
|
|
196
159
|
for (const query of queries.filter(query => !mediaQueryLists[query])) {
|
|
197
160
|
mediaQueryLists[query] = window.matchMedia(query);
|
|
198
161
|
}
|
|
199
|
-
}
|
|
200
|
-
// If an override has been specified, we use that.
|
|
201
|
-
// If we're rendering on the server then we use the default
|
|
202
|
-
// SSR rendering size.
|
|
203
|
-
// Otherwise we attempt to get the current size based on
|
|
204
|
-
// the current MediaSpec.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const mediaSize = overrideSize || this.isServerSide() && ssrSize || this.getCurrentSize(mediaSpec); // Generate a mock stylesheet
|
|
162
|
+
}
|
|
208
163
|
|
|
164
|
+
const mediaSize = overrideSize || this.isServerSide() && ssrSize || this.getCurrentSize(mediaSpec);
|
|
209
165
|
const styles = this.getMockStyleSheet(mediaSize);
|
|
210
166
|
return children({
|
|
211
167
|
mediaSize,
|
|
@@ -214,19 +170,15 @@ class MediaLayoutInternal extends Component {
|
|
|
214
170
|
});
|
|
215
171
|
}
|
|
216
172
|
|
|
217
|
-
}
|
|
218
|
-
|
|
173
|
+
}
|
|
219
174
|
|
|
220
|
-
class MediaLayout extends Component {
|
|
175
|
+
class MediaLayout extends React.Component {
|
|
221
176
|
render() {
|
|
222
|
-
|
|
223
|
-
// being given (this can be overriden by wrapping this component in
|
|
224
|
-
// a MediaLayoutContext.Consumer).
|
|
225
|
-
return /*#__PURE__*/createElement(MediaLayoutContext.Consumer, null, ({
|
|
177
|
+
return React.createElement(MediaLayoutContext.Consumer, null, ({
|
|
226
178
|
overrideSize,
|
|
227
179
|
ssrSize,
|
|
228
180
|
mediaSpec
|
|
229
|
-
}) =>
|
|
181
|
+
}) => React.createElement(MediaLayoutInternal, _extends({}, this.props, {
|
|
230
182
|
overrideSize: overrideSize,
|
|
231
183
|
ssrSize: ssrSize,
|
|
232
184
|
mediaSpec: mediaSpec
|
|
@@ -235,17 +187,12 @@ class MediaLayout extends Component {
|
|
|
235
187
|
|
|
236
188
|
}
|
|
237
189
|
|
|
238
|
-
|
|
239
|
-
* Expands to fill space between sibling components.
|
|
240
|
-
*
|
|
241
|
-
* Assumes parent is a View.
|
|
242
|
-
*/
|
|
243
|
-
class Spring extends Component {
|
|
190
|
+
class Spring extends React.Component {
|
|
244
191
|
render() {
|
|
245
192
|
const {
|
|
246
193
|
style
|
|
247
194
|
} = this.props;
|
|
248
|
-
return
|
|
195
|
+
return React.createElement(View, {
|
|
249
196
|
"aria-hidden": "true",
|
|
250
197
|
style: [styles.grow, style]
|
|
251
198
|
});
|
|
@@ -258,18 +205,13 @@ const styles = StyleSheet.create({
|
|
|
258
205
|
}
|
|
259
206
|
});
|
|
260
207
|
|
|
261
|
-
|
|
262
|
-
* A component for inserting fixed space between components.
|
|
263
|
-
*
|
|
264
|
-
* Assumes parent is a View.
|
|
265
|
-
*/
|
|
266
|
-
class Strut extends Component {
|
|
208
|
+
class Strut extends React.Component {
|
|
267
209
|
render() {
|
|
268
210
|
const {
|
|
269
211
|
size,
|
|
270
212
|
style
|
|
271
213
|
} = this.props;
|
|
272
|
-
return
|
|
214
|
+
return React.createElement(View, {
|
|
273
215
|
"aria-hidden": "true",
|
|
274
216
|
style: [strutStyle(size), style]
|
|
275
217
|
});
|
|
@@ -288,16 +230,6 @@ const strutStyle = size => {
|
|
|
288
230
|
};
|
|
289
231
|
};
|
|
290
232
|
|
|
291
|
-
/**
|
|
292
|
-
* Return where a media size matches a media query.
|
|
293
|
-
*
|
|
294
|
-
* examples:
|
|
295
|
-
* - `queryMatchesSize("all", "small")` returns `true`
|
|
296
|
-
* - `queryMatchesSize("mdOrLarger", "small")` returns `false`
|
|
297
|
-
*
|
|
298
|
-
* @param {MediaQuery} mediaQuery
|
|
299
|
-
* @param {MediaSize} mediaSize
|
|
300
|
-
*/
|
|
301
233
|
const queryMatchesSize = (mediaQuery, mediaSize) => {
|
|
302
234
|
switch (mediaQuery) {
|
|
303
235
|
case "all":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-layout",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.9",
|
|
4
4
|
"design": "v1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -14,17 +14,16 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@babel/runtime": "^7.16.3",
|
|
17
|
-
"@khanacademy/wonder-blocks-core": "^4.
|
|
17
|
+
"@khanacademy/wonder-blocks-core": "^4.3.1",
|
|
18
18
|
"@khanacademy/wonder-blocks-spacing": "^3.0.5"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"wb-dev-build-settings": "^0.
|
|
21
|
+
"wb-dev-build-settings": "^0.4.0"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"aphrodite": "^1.2.5",
|
|
25
25
|
"react": "16.14.0"
|
|
26
26
|
},
|
|
27
27
|
"author": "",
|
|
28
|
-
"license": "MIT"
|
|
29
|
-
"gitHead": "9ebea88533e702011165072f090a377e02fa3f0f"
|
|
28
|
+
"license": "MIT"
|
|
30
29
|
}
|
|
@@ -22,8 +22,8 @@ exports[`wonder-blocks-layout example 1 1`] = `
|
|
|
22
22
|
}
|
|
23
23
|
>
|
|
24
24
|
<button
|
|
25
|
+
aria-disabled={false}
|
|
25
26
|
className=""
|
|
26
|
-
disabled={false}
|
|
27
27
|
onBlur={[Function]}
|
|
28
28
|
onClick={[Function]}
|
|
29
29
|
onDragStart={[Function]}
|
|
@@ -121,8 +121,8 @@ exports[`wonder-blocks-layout example 1 1`] = `
|
|
|
121
121
|
}
|
|
122
122
|
/>
|
|
123
123
|
<button
|
|
124
|
+
aria-disabled={false}
|
|
124
125
|
className=""
|
|
125
|
-
disabled={false}
|
|
126
126
|
onBlur={[Function]}
|
|
127
127
|
onClick={[Function]}
|
|
128
128
|
onDragStart={[Function]}
|
|
@@ -220,8 +220,8 @@ exports[`wonder-blocks-layout example 1 1`] = `
|
|
|
220
220
|
}
|
|
221
221
|
/>
|
|
222
222
|
<button
|
|
223
|
+
aria-disabled={false}
|
|
223
224
|
className=""
|
|
224
|
-
disabled={false}
|
|
225
225
|
onBlur={[Function]}
|
|
226
226
|
onClick={[Function]}
|
|
227
227
|
onDragStart={[Function]}
|
|
@@ -314,8 +314,8 @@ exports[`wonder-blocks-layout example 1 1`] = `
|
|
|
314
314
|
}
|
|
315
315
|
/>
|
|
316
316
|
<button
|
|
317
|
+
aria-disabled={false}
|
|
317
318
|
className=""
|
|
318
|
-
disabled={false}
|
|
319
319
|
onBlur={[Function]}
|
|
320
320
|
onClick={[Function]}
|
|
321
321
|
onDragStart={[Function]}
|
|
@@ -413,8 +413,8 @@ exports[`wonder-blocks-layout example 1 1`] = `
|
|
|
413
413
|
}
|
|
414
414
|
/>
|
|
415
415
|
<button
|
|
416
|
+
aria-disabled={false}
|
|
416
417
|
className=""
|
|
417
|
-
disabled={false}
|
|
418
418
|
onBlur={[Function]}
|
|
419
419
|
onClick={[Function]}
|
|
420
420
|
onDragStart={[Function]}
|
|
@@ -3,6 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import {StyleSheet} from "aphrodite";
|
|
4
4
|
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
5
|
import {mount} from "enzyme";
|
|
6
|
+
import "jest-enzyme";
|
|
6
7
|
|
|
7
8
|
import MediaLayout from "../media-layout.js";
|
|
8
9
|
import {resizeWindow, matchMedia} from "../../util/test-util.js";
|
|
@@ -32,7 +32,7 @@ const styles = StyleSheet.create({
|
|
|
32
32
|
},
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
export const
|
|
35
|
+
export const Simple: StoryComponentType = () => (
|
|
36
36
|
<View style={styles.column}>
|
|
37
37
|
<View style={styles.row}>
|
|
38
38
|
<Button>Hello, world!</Button>
|
|
@@ -48,7 +48,7 @@ export const simple: StoryComponentType = () => (
|
|
|
48
48
|
</View>
|
|
49
49
|
);
|
|
50
50
|
|
|
51
|
-
export const
|
|
51
|
+
export const WithStyle: StoryComponentType = () => (
|
|
52
52
|
<View style={styles.column}>
|
|
53
53
|
<View style={styles.row}>
|
|
54
54
|
<Button>Hello, world!</Button>
|
|
@@ -68,14 +68,14 @@ export const withStyle: StoryComponentType = () => (
|
|
|
68
68
|
</View>
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
Simple.parameters = {
|
|
72
72
|
chromatic: {
|
|
73
73
|
// we don't need screenshots because this story only tests behavior.
|
|
74
74
|
disableSnapshot: true,
|
|
75
75
|
},
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
WithStyle.parameters = {
|
|
79
79
|
chromatic: {
|
|
80
80
|
// we don't need screenshots because this story only tests behavior.
|
|
81
81
|
disableSnapshot: true,
|
|
@@ -36,7 +36,7 @@ const styles = StyleSheet.create({
|
|
|
36
36
|
const smallSize = Spacing.medium_16;
|
|
37
37
|
const largeSize = Spacing.xxxLarge_64;
|
|
38
38
|
|
|
39
|
-
export const
|
|
39
|
+
export const Simple: StoryComponentType = () => (
|
|
40
40
|
<View style={styles.column}>
|
|
41
41
|
<View style={styles.row}>
|
|
42
42
|
<Button>Hello, world!</Button>
|
|
@@ -59,7 +59,7 @@ export const simple: StoryComponentType = () => (
|
|
|
59
59
|
</View>
|
|
60
60
|
);
|
|
61
61
|
|
|
62
|
-
export const
|
|
62
|
+
export const WithStyle: StoryComponentType = () => (
|
|
63
63
|
<View style={styles.column}>
|
|
64
64
|
<View style={styles.row}>
|
|
65
65
|
<Button>Hello, world!</Button>
|
|
@@ -83,14 +83,14 @@ export const withStyle: StoryComponentType = () => (
|
|
|
83
83
|
</View>
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
Simple.parameters = {
|
|
87
87
|
chromatic: {
|
|
88
88
|
// we don't need screenshots because this story only tests behavior.
|
|
89
89
|
disableSnapshot: true,
|
|
90
90
|
},
|
|
91
91
|
};
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
WithStyle.parameters = {
|
|
94
94
|
chromatic: {
|
|
95
95
|
// we don't need screenshots because this story only tests behavior.
|
|
96
96
|
disableSnapshot: true,
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2018 Khan Academy
|
|
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.
|