@thinkpixellab-public/px-vue 3.0.4 → 3.0.6
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/components/PxAspect.vue +1 -1
- package/components/PxCardGrid.vue +126 -33
- package/components/PxContain.vue +260 -0
- package/components/PxFloat.vue +1 -2
- package/dev/demos/Demo-PxCardGrid.vue +2 -0
- package/dev/demos/Demo-PxContain.vue +116 -0
- package/dev/dev.vue +2 -0
- package/package.json +1 -1
- package/utils/fit.js +2 -2
package/components/PxAspect.vue
CHANGED
|
@@ -18,7 +18,7 @@ export default {
|
|
|
18
18
|
name: 'px-aspect',
|
|
19
19
|
mixins: [PxBaseResize],
|
|
20
20
|
props: {
|
|
21
|
-
// the aspect ration (can be express as a number or a
|
|
21
|
+
// the aspect ration (can be express as a number or a ratio string like '16:9')
|
|
22
22
|
aspect: { default: 16 / 9 },
|
|
23
23
|
|
|
24
24
|
// the horizontal positioning when there is leftover space
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The grid will be created to contain cells (like a spreadsheet). A space represents an area that
|
|
4
4
|
spans a certain number of cells and can contain a certain number of cards. Keeping all of this
|
|
5
|
-
straight can get a little confusing because the terms are highly related but different, so here
|
|
6
|
-
|
|
5
|
+
straight can get a little confusing because the terms are highly related but different, so here is
|
|
6
|
+
the breakdown in some detail:
|
|
7
7
|
|
|
8
8
|
## Cell
|
|
9
9
|
A single unit in the grid that spans 1 row and 1 column.
|
|
@@ -16,6 +16,11 @@ spaces can only span columns (not rows). We support three kinds of spaces:
|
|
|
16
16
|
- **stacked** space ('==') This space is also (1x1) but contains two cards stacked vertically.
|
|
17
17
|
- **wide** space ('-----') This space is 2x1 cells and contains one card.
|
|
18
18
|
|
|
19
|
+
You might be wondering why we don't just make space and cell the same thing and the largest cards
|
|
20
|
+
would be 2x2 instead of 1x2. It has to do with the way we're using css grid for layout. Things are a
|
|
21
|
+
lot cleaner if our max card height is a single row in the grid. It also makes it so that the
|
|
22
|
+
notation matches the rows array which keeps things easier to understand.`
|
|
23
|
+
|
|
19
24
|
## Card
|
|
20
25
|
Cards are areas within a space. Default and wide spaces contain a single card. Stacked spaces
|
|
21
26
|
contain two cards.
|
|
@@ -50,6 +55,48 @@ You can define a template using space notation like this:
|
|
|
50
55
|
<template #default="{ item }">{{ item.name }}</template>
|
|
51
56
|
</px-card-grid>
|
|
52
57
|
|
|
58
|
+
|
|
59
|
+
## Custom Item Selection
|
|
60
|
+
|
|
61
|
+
By default items will be placed in the template in sequential order but it's possible to take
|
|
62
|
+
full control of which item is placed in which slot but providing a callback with the getItemFn
|
|
63
|
+
property. This function will receive an object with parameters describing the space and expects
|
|
64
|
+
an item to be returned. The function will be called once for the number of spaces in the layout
|
|
65
|
+
(include for orphans).
|
|
66
|
+
|
|
67
|
+
When using this method it isn't even necessary to set the items property but you also need to
|
|
68
|
+
provide the getItemCountFn callback. That should be the number of items without orphans (you will
|
|
69
|
+
still get the callback for orphans).
|
|
70
|
+
|
|
71
|
+
<px-card-grid
|
|
72
|
+
:gap="30"
|
|
73
|
+
:maxColumns="4"
|
|
74
|
+
:debug="true",
|
|
75
|
+
:templates="{
|
|
76
|
+
4: ['== -- -----', '-- == -- --', '----- -- ==', '-- -- == --'],
|
|
77
|
+
3: ['== -- --', '-- -- ==', '-- == --'],
|
|
78
|
+
2: ['-- --', '-----', '== --'],
|
|
79
|
+
}"
|
|
80
|
+
:get-item-fn="getItem"
|
|
81
|
+
:get-item-count="getItemCount"
|
|
82
|
+
>
|
|
83
|
+
<template #default="{ item }">{{ item.name }}</template>
|
|
84
|
+
</px-card-grid>
|
|
85
|
+
|
|
86
|
+
getItem(space) {
|
|
87
|
+
if (space.type == 'stacked') {
|
|
88
|
+
...
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
...
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getItemCount() {
|
|
96
|
+
return ...;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
53
100
|
-->
|
|
54
101
|
|
|
55
102
|
<template>
|
|
@@ -131,6 +178,13 @@ const spaceTemplateToSpaceRows = rows => {
|
|
|
131
178
|
return spaces;
|
|
132
179
|
};
|
|
133
180
|
|
|
181
|
+
const cardCountInRowTemplate = rowTemplate => {
|
|
182
|
+
let count = rowTemplate.reduce((total, space) => {
|
|
183
|
+
return total + space.cards;
|
|
184
|
+
}, 0);
|
|
185
|
+
return count;
|
|
186
|
+
};
|
|
187
|
+
|
|
134
188
|
export default {
|
|
135
189
|
name: 'px-card-grid',
|
|
136
190
|
// components: { Component },
|
|
@@ -146,6 +200,8 @@ export default {
|
|
|
146
200
|
cardAspect: { default: 3 / 4 },
|
|
147
201
|
gap: { type: Number, default: 24 },
|
|
148
202
|
debug: { type: Boolean, default: false },
|
|
203
|
+
getItemCountFn: { default: null },
|
|
204
|
+
getItemFn: { default: null },
|
|
149
205
|
},
|
|
150
206
|
|
|
151
207
|
data() {
|
|
@@ -175,7 +231,9 @@ export default {
|
|
|
175
231
|
// Returns an array of rows, each of which contains an array of spaces each
|
|
176
232
|
// of which contains 1 or more items that can be used to create cards.
|
|
177
233
|
|
|
178
|
-
|
|
234
|
+
let itemCount = this.getItemCount();
|
|
235
|
+
|
|
236
|
+
if (!this.rowTemplates || !itemCount || this.columnCount == 0) {
|
|
179
237
|
return [];
|
|
180
238
|
}
|
|
181
239
|
|
|
@@ -191,39 +249,58 @@ export default {
|
|
|
191
249
|
let rowIndex = 0;
|
|
192
250
|
let itemIndex = 0;
|
|
193
251
|
|
|
194
|
-
while (itemIndex <
|
|
252
|
+
while (itemIndex < itemCount && rowIndex < 1000) {
|
|
195
253
|
let template = templates[rowIndex % templates.length];
|
|
254
|
+
let rowCardCount = cardCountInRowTemplate(template);
|
|
255
|
+
let isOrphanRow = itemIndex + rowCardCount > itemCount;
|
|
256
|
+
|
|
257
|
+
// render if this is not an orphan row or it is and we allow it
|
|
258
|
+
if (!isOrphanRow || this.allowOrphans) {
|
|
259
|
+
let row = template.map(spaceTemplate => {
|
|
260
|
+
let cards = Array(spaceTemplate.cards).fill(0);
|
|
261
|
+
|
|
262
|
+
cards = cards.map(() => {
|
|
263
|
+
let item = null;
|
|
264
|
+
const isOrphanPadding = itemIndex >= itemCount;
|
|
265
|
+
const isOrphan = isOrphanRow && !isOrphanPadding;
|
|
266
|
+
|
|
267
|
+
if (!isOrphanPadding || this.padOrphans) {
|
|
268
|
+
item = this.getItemForSpace({
|
|
269
|
+
index: itemIndex,
|
|
270
|
+
type: spaceTemplate.name,
|
|
271
|
+
orphan: isOrphan,
|
|
272
|
+
orphanPadding: isOrphanPadding,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
itemIndex++;
|
|
277
|
+
return item;
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
name: spaceTemplate.name,
|
|
282
|
+
cardCount: spaceTemplate.cards,
|
|
283
|
+
cards: cards,
|
|
284
|
+
};
|
|
285
|
+
});
|
|
196
286
|
|
|
197
|
-
|
|
198
|
-
|
|
287
|
+
rows.push(row);
|
|
288
|
+
}
|
|
199
289
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
});
|
|
290
|
+
// get out of the loop
|
|
291
|
+
else {
|
|
292
|
+
itemIndex += rowCardCount;
|
|
293
|
+
}
|
|
205
294
|
|
|
206
|
-
return {
|
|
207
|
-
name: spaceTemplate.name,
|
|
208
|
-
cardCount: spaceTemplate.cards,
|
|
209
|
-
cards: cards,
|
|
210
|
-
};
|
|
211
|
-
});
|
|
212
|
-
rows.push(row);
|
|
213
295
|
rowIndex++;
|
|
214
296
|
}
|
|
215
297
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
rows[rows.length - 1] = rows[rows.length - 1].filter(sp => {
|
|
223
|
-
sp.cards = sp.cards.filter(card => !!card);
|
|
224
|
-
return sp.cards.length;
|
|
225
|
-
});
|
|
226
|
-
}
|
|
298
|
+
if (!this.padOrphans && itemIndex > itemCount) {
|
|
299
|
+
// remove empty
|
|
300
|
+
rows[rows.length - 1] = rows[rows.length - 1].filter(sp => {
|
|
301
|
+
sp.cards = sp.cards.filter(card => !!card);
|
|
302
|
+
return sp.cards.length;
|
|
303
|
+
});
|
|
227
304
|
}
|
|
228
305
|
|
|
229
306
|
return rows;
|
|
@@ -248,14 +325,30 @@ export default {
|
|
|
248
325
|
delete this.resizeObserver;
|
|
249
326
|
},
|
|
250
327
|
methods: {
|
|
251
|
-
|
|
328
|
+
getItemCount() {
|
|
329
|
+
if (this.getItemCountFn) {
|
|
330
|
+
return this.getItemCountFn();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return this.items.length;
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
getItemForSpace(space) {
|
|
337
|
+
if (this.getItemFn) {
|
|
338
|
+
return this.getItemFn(space);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (space.orphanPadding) {
|
|
342
|
+
return space;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const index = space.index;
|
|
346
|
+
|
|
252
347
|
if (this.items && index < this.items.length) {
|
|
253
348
|
return this.items[index];
|
|
254
349
|
}
|
|
255
350
|
|
|
256
|
-
|
|
257
|
-
debugger;
|
|
258
|
-
}
|
|
351
|
+
console.warn(`No item found for space at index ${index}.`);
|
|
259
352
|
return null;
|
|
260
353
|
},
|
|
261
354
|
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Keeps a child element contained within boundaries.
|
|
3
|
+
|
|
4
|
+
<px-contain #default="{width, height, left: }" :aspect="16/9" :round="true" :to-px="true">
|
|
5
|
+
<div :style="{position: 'absolute', left: left top: top width: width height: height}" />
|
|
6
|
+
</px-contain>
|
|
7
|
+
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div :class="bem()">
|
|
12
|
+
<slot
|
|
13
|
+
name="default"
|
|
14
|
+
:top="contain.top"
|
|
15
|
+
:right="contain.right"
|
|
16
|
+
:left="contain.left"
|
|
17
|
+
:bottom="contain.bottom"
|
|
18
|
+
:width="contain.width"
|
|
19
|
+
:height="contain.height"
|
|
20
|
+
:scale="contain.scale"
|
|
21
|
+
></slot>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
import { contain } from '../utils/fit';
|
|
27
|
+
import aspectFilter from '../plugins/filters/aspect.js';
|
|
28
|
+
import PxBaseResize from './PxBaseResize.vue';
|
|
29
|
+
|
|
30
|
+
export default {
|
|
31
|
+
name: 'px-contain',
|
|
32
|
+
mixins: [PxBaseResize],
|
|
33
|
+
|
|
34
|
+
props: {
|
|
35
|
+
// an optional aspect ratio that should be maintained when calculating size and position, if
|
|
36
|
+
// not provided then width and height will always cover the full outer container (can be a
|
|
37
|
+
// number or ratio string like '16:9')
|
|
38
|
+
aspect: { default: null },
|
|
39
|
+
|
|
40
|
+
// if either of these is provided, then slot values will also include a value for scale
|
|
41
|
+
// which is the relative scale of the container compared to the natural size of the object;
|
|
42
|
+
// note also that aspect/width/height benefits all become available if just 2 of 3
|
|
43
|
+
// properties have been defined
|
|
44
|
+
naturalWidth: { type: Number, default: null },
|
|
45
|
+
naturalHeight: { type: Number, default: null },
|
|
46
|
+
|
|
47
|
+
// these are adjustments to the available area inside of the container rectangle; the
|
|
48
|
+
// difference between padding and border is that padding values will also affect the final
|
|
49
|
+
// top/left values but border does not (to visualize this, imagine that you use border if
|
|
50
|
+
// the content has a visible border around and the final values reflect that where padding
|
|
51
|
+
// is empty space so palcement gets shfited); specify as either a number or an arry of up to
|
|
52
|
+
// 4 numbers that follow the css box-model pattern
|
|
53
|
+
padding: { default: null },
|
|
54
|
+
border: { default: null },
|
|
55
|
+
|
|
56
|
+
// the horizontal positioning when there is leftover space
|
|
57
|
+
alignX: { default: 0.5 }, // number | 'start' | 'center' | 'end'
|
|
58
|
+
|
|
59
|
+
// the vertical positioning when there is leftover space
|
|
60
|
+
alignY: { default: 0.5 }, // number | 'start' | 'center' | 'end'
|
|
61
|
+
|
|
62
|
+
// whether slot values should be returned as strings with 'px'
|
|
63
|
+
toPx: { type: Boolean, default: true },
|
|
64
|
+
|
|
65
|
+
// whether slot values should be rounded to screen pixels
|
|
66
|
+
round: { type: Boolean, default: true },
|
|
67
|
+
},
|
|
68
|
+
data() {
|
|
69
|
+
return {
|
|
70
|
+
contain: {
|
|
71
|
+
current: false,
|
|
72
|
+
width: 0,
|
|
73
|
+
height: 0,
|
|
74
|
+
top: 0,
|
|
75
|
+
right: 0,
|
|
76
|
+
bottom: 0,
|
|
77
|
+
left: 0,
|
|
78
|
+
scale: 1,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
computed: {
|
|
83
|
+
aspectNumber() {
|
|
84
|
+
return aspectFilter(this.aspect);
|
|
85
|
+
},
|
|
86
|
+
aspectRect() {
|
|
87
|
+
let a = this.aspect ? this.aspectNumber : null;
|
|
88
|
+
let w = this.naturalWidth;
|
|
89
|
+
let h = this.naturalHeight;
|
|
90
|
+
|
|
91
|
+
// width and height (ignore aspect)
|
|
92
|
+
if (w && h) {
|
|
93
|
+
return {
|
|
94
|
+
width: w,
|
|
95
|
+
height: h,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// just aspect (no width or height)
|
|
100
|
+
if (!w && !h && a) {
|
|
101
|
+
return {
|
|
102
|
+
width: a,
|
|
103
|
+
height: 1,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// width and aspect, infer height
|
|
108
|
+
if (w && a && !h) {
|
|
109
|
+
return {
|
|
110
|
+
width: w,
|
|
111
|
+
height: w * (1 / a),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// height and aspect, infer width
|
|
116
|
+
if (w && a && !h) {
|
|
117
|
+
return {
|
|
118
|
+
width: h * a,
|
|
119
|
+
height: h,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// no width or height or aspect
|
|
124
|
+
return null;
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
watch: {
|
|
129
|
+
aspectNumber() {
|
|
130
|
+
this.resize();
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
methods: {
|
|
134
|
+
resize() {
|
|
135
|
+
let p = this.toBoxModelObject(this.padding);
|
|
136
|
+
|
|
137
|
+
let b = this.toBoxModelObject(this.border);
|
|
138
|
+
let outer = this.$el.getBoundingClientRect();
|
|
139
|
+
let inner = this.aspectRect || outer;
|
|
140
|
+
|
|
141
|
+
outer = {
|
|
142
|
+
width: outer.width - (b.w + p.w),
|
|
143
|
+
height: outer.height - (b.h + p.h),
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
let r;
|
|
147
|
+
|
|
148
|
+
if (this.aspect) {
|
|
149
|
+
r = contain(
|
|
150
|
+
inner,
|
|
151
|
+
outer,
|
|
152
|
+
this.alignToDecimal(this.alignX),
|
|
153
|
+
this.alignToDecimal(this.alignY)
|
|
154
|
+
);
|
|
155
|
+
} else {
|
|
156
|
+
r = {
|
|
157
|
+
x: 0,
|
|
158
|
+
y: 0,
|
|
159
|
+
width: outer.width,
|
|
160
|
+
height: outer.height,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let c = {
|
|
165
|
+
current: true,
|
|
166
|
+
width: r.width + b.w,
|
|
167
|
+
height: r.height + b.h,
|
|
168
|
+
top: r.y + p.top,
|
|
169
|
+
left: r.x + p.left,
|
|
170
|
+
right: r.width - (r.x + b.w),
|
|
171
|
+
bottom: r.height - (r.y + b.h),
|
|
172
|
+
scale: this.naturalWidth || this.naturalHeight ? r.scale : 1,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
this.$emit('update', c);
|
|
176
|
+
|
|
177
|
+
c.width = this.prepValue(c.width);
|
|
178
|
+
c.height = this.prepValue(c.height);
|
|
179
|
+
c.left = this.prepValue(c.left);
|
|
180
|
+
c.top = this.prepValue(c.top);
|
|
181
|
+
c.right = this.prepValue(c.right);
|
|
182
|
+
c.bottom = this.prepValue(c.bottom);
|
|
183
|
+
|
|
184
|
+
this.contain = c;
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
prepValue(n) {
|
|
188
|
+
if (this.round && typeof window != 'undefined') {
|
|
189
|
+
n = Math.round(n * window.devicePixelRatio) / window.devicePixelRatio;
|
|
190
|
+
}
|
|
191
|
+
if (this.toPx) {
|
|
192
|
+
n = this.cssPx(n);
|
|
193
|
+
}
|
|
194
|
+
return n;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
toBoxModelObject(val) {
|
|
198
|
+
const arr = this.toBoxModelArray(val);
|
|
199
|
+
return {
|
|
200
|
+
top: arr[0],
|
|
201
|
+
right: arr[1],
|
|
202
|
+
bottom: arr[2],
|
|
203
|
+
left: arr[3],
|
|
204
|
+
w: arr[1] + arr[3],
|
|
205
|
+
h: arr[0] + arr[2],
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
toBoxModelArray(val) {
|
|
210
|
+
if (!val) {
|
|
211
|
+
return [0, 0, 0, 0];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (Array.isArray(val)) {
|
|
215
|
+
if (val.length == 0) {
|
|
216
|
+
return [0, 0, 0, 0];
|
|
217
|
+
}
|
|
218
|
+
if (val.length == 1) {
|
|
219
|
+
return [val[0], val[0], val[0], val[0]];
|
|
220
|
+
}
|
|
221
|
+
if (val.length == 2) {
|
|
222
|
+
return [val[0], val[1], val[0], val[1]];
|
|
223
|
+
}
|
|
224
|
+
if (val.length == 3) {
|
|
225
|
+
return [val[0], val[1], val[2], val[1]];
|
|
226
|
+
}
|
|
227
|
+
return [val[0], val[1], val[2], val[3]];
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return [val, val, val, val];
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
alignToDecimal(align) {
|
|
234
|
+
if (typeof align == 'number') {
|
|
235
|
+
return align;
|
|
236
|
+
}
|
|
237
|
+
if (align === 'center') {
|
|
238
|
+
return 0.5;
|
|
239
|
+
}
|
|
240
|
+
if (align === 'start') {
|
|
241
|
+
return 0;
|
|
242
|
+
}
|
|
243
|
+
if (align === 'end') {
|
|
244
|
+
return 1;
|
|
245
|
+
}
|
|
246
|
+
const float = parseFloat(align);
|
|
247
|
+
return !isNaN(float) ? float : 0.5;
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
</script>
|
|
252
|
+
|
|
253
|
+
<style lang="scss">
|
|
254
|
+
@use '../styles/px.scss' as *;
|
|
255
|
+
.px-contain {
|
|
256
|
+
width: 100%;
|
|
257
|
+
height: 100%;
|
|
258
|
+
position: relative;
|
|
259
|
+
}
|
|
260
|
+
</style>
|
package/components/PxFloat.vue
CHANGED
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
:name="calcTransitionName"
|
|
23
23
|
@before-enter="transitionVisible = true"
|
|
24
24
|
@after-leave="transitionVisible = false"
|
|
25
|
-
:style="{ zIndex: zStart + currentLayerIndex }"
|
|
26
25
|
>
|
|
27
26
|
<div
|
|
28
27
|
:class="bem({ ...variantsMap, absolute: strategy == 'absolute' })"
|
|
28
|
+
:style="{ zIndex: zStart + currentLayerIndex }"
|
|
29
29
|
v-show="visibleValueNext"
|
|
30
30
|
>
|
|
31
31
|
<!-- overlay element -->
|
|
@@ -273,7 +273,6 @@ export default {
|
|
|
273
273
|
}
|
|
274
274
|
} else {
|
|
275
275
|
if (this.cleanup) {
|
|
276
|
-
console.log('cleanup');
|
|
277
276
|
this.cleanup();
|
|
278
277
|
this.cleanup = null;
|
|
279
278
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
:debug="true"
|
|
9
9
|
:gap="60"
|
|
10
10
|
:allow-orphans="true"
|
|
11
|
+
:pad-orphans="true"
|
|
11
12
|
:maxColumns="4"
|
|
12
13
|
:templates="{
|
|
13
14
|
4: ['== -- -----', '-- == -- --', '----- -- ==', '-- -- == --'],
|
|
@@ -49,5 +50,6 @@ export default {
|
|
|
49
50
|
<style lang="scss">
|
|
50
51
|
.demo-px-card-grid {
|
|
51
52
|
// add styles here
|
|
53
|
+
padding: 5vh 0 10vh;
|
|
52
54
|
}
|
|
53
55
|
</style>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Describe this component...
|
|
3
|
+
-->
|
|
4
|
+
<template>
|
|
5
|
+
<div :class="bem()">
|
|
6
|
+
<px-tester>
|
|
7
|
+
<px-test name="Aspect" testId="pxcontain-aspect" :size="{ h: 600 }">
|
|
8
|
+
<px-contain aspect="16:9" :px="true">
|
|
9
|
+
<template #default="{ top, left, width, height }">
|
|
10
|
+
<div
|
|
11
|
+
:style="{
|
|
12
|
+
position: 'absolute',
|
|
13
|
+
left,
|
|
14
|
+
top,
|
|
15
|
+
width,
|
|
16
|
+
height,
|
|
17
|
+
background: 'red',
|
|
18
|
+
}"
|
|
19
|
+
/>
|
|
20
|
+
</template>
|
|
21
|
+
</px-contain>
|
|
22
|
+
</px-test>
|
|
23
|
+
|
|
24
|
+
<px-test name="Width / Height" testId="pxcontain-wh" :size="{ h: 600 }">
|
|
25
|
+
<px-contain :naturalWidth="1600" :naturalHeight="900">
|
|
26
|
+
<template #default="{ top, left, width, height }">
|
|
27
|
+
<div
|
|
28
|
+
:style="{
|
|
29
|
+
position: 'absolute',
|
|
30
|
+
left,
|
|
31
|
+
top,
|
|
32
|
+
width,
|
|
33
|
+
height,
|
|
34
|
+
background: 'gold',
|
|
35
|
+
}"
|
|
36
|
+
/>
|
|
37
|
+
</template>
|
|
38
|
+
</px-contain>
|
|
39
|
+
</px-test>
|
|
40
|
+
|
|
41
|
+
<px-test name="Scale" testId="pxcontain-scale" :size="{ h: 600 }">
|
|
42
|
+
<px-contain :naturalWidth="1600" :naturalHeight="900">
|
|
43
|
+
<template #default="{ top, left, scale }">
|
|
44
|
+
<div
|
|
45
|
+
:style="{
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
width: '1600px',
|
|
48
|
+
height: '900px',
|
|
49
|
+
top,
|
|
50
|
+
left,
|
|
51
|
+
transformOrigin: '0 0',
|
|
52
|
+
transform: `scale(${scale})`,
|
|
53
|
+
background: 'gold',
|
|
54
|
+
}"
|
|
55
|
+
/>
|
|
56
|
+
</template>
|
|
57
|
+
</px-contain>
|
|
58
|
+
</px-test>
|
|
59
|
+
<px-test name="Basic with Padding" testId="pxcontain-pad" :size="{ h: 600 }">
|
|
60
|
+
<div
|
|
61
|
+
:style="{
|
|
62
|
+
width: '100%',
|
|
63
|
+
height: '100%',
|
|
64
|
+
padding: '49px',
|
|
65
|
+
border: '1px solid red',
|
|
66
|
+
boxSizing: 'border-box',
|
|
67
|
+
}"
|
|
68
|
+
>
|
|
69
|
+
<px-contain :aspect="4 / 3">
|
|
70
|
+
<template #default="{ top, left, width, height }">
|
|
71
|
+
<div
|
|
72
|
+
:style="{
|
|
73
|
+
position: 'absolute',
|
|
74
|
+
left,
|
|
75
|
+
top,
|
|
76
|
+
width,
|
|
77
|
+
height,
|
|
78
|
+
background: 'lightblue',
|
|
79
|
+
}"
|
|
80
|
+
>
|
|
81
|
+
{{ width }} x {{ height }}
|
|
82
|
+
</div>
|
|
83
|
+
</template>
|
|
84
|
+
</px-contain>
|
|
85
|
+
</div>
|
|
86
|
+
</px-test>
|
|
87
|
+
</px-tester>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<script>
|
|
92
|
+
// import { mapState } from 'vuex';
|
|
93
|
+
// import Component from '~/components/Component.vue';
|
|
94
|
+
// import Mixin from '~/components/Mixin.vue';
|
|
95
|
+
import { PxTester, PxTest } from '@thinkpixellab-public/px-vue-tester';
|
|
96
|
+
import PxContain from '../../components/PxContain.vue';
|
|
97
|
+
|
|
98
|
+
export default {
|
|
99
|
+
name: 'demo-px-contain',
|
|
100
|
+
components: { PxTester, PxTest, PxContain },
|
|
101
|
+
// mixins: [ Mixin ],
|
|
102
|
+
// props: { a: { type: Boolean, default: false } },
|
|
103
|
+
// data() { return { b: 0 }; },
|
|
104
|
+
// computed: {},
|
|
105
|
+
// watch: {},
|
|
106
|
+
// mounted() {},
|
|
107
|
+
// methods: {},
|
|
108
|
+
};
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<style lang="scss">
|
|
112
|
+
//@import '@/styles/include.scss';
|
|
113
|
+
.demo-px-contain {
|
|
114
|
+
// add styles here
|
|
115
|
+
}
|
|
116
|
+
</style>
|
package/dev/dev.vue
CHANGED
|
@@ -17,6 +17,7 @@ import DemoPxBaseDrag from './demos/Demo-PxBaseDrag.vue';
|
|
|
17
17
|
import DemoPxStylesPreview from './demos/Demo-PxStylesPreview.vue';
|
|
18
18
|
import DemoPxPivot from './demos/Demo-PxPivot.vue';
|
|
19
19
|
import DemoPxFloat from './demos/Demo-PxFloat.vue';
|
|
20
|
+
import DemoPxContain from './demos/Demo-PxContain.vue';
|
|
20
21
|
|
|
21
22
|
export default Vue.extend({
|
|
22
23
|
components: {
|
|
@@ -30,6 +31,7 @@ export default Vue.extend({
|
|
|
30
31
|
DemoPxStylesPreview,
|
|
31
32
|
DemoPxPivot,
|
|
32
33
|
DemoPxFloat,
|
|
34
|
+
DemoPxContain,
|
|
33
35
|
},
|
|
34
36
|
name: 'ServeDev',
|
|
35
37
|
data() {
|
package/package.json
CHANGED
package/utils/fit.js
CHANGED
|
@@ -52,13 +52,13 @@ export function contain(inner, outer, posX = 0.5, posY = 0.5) {
|
|
|
52
52
|
height = outer.width / aspectInner;
|
|
53
53
|
x = 0;
|
|
54
54
|
y = outer.height * posY - height * posY;
|
|
55
|
-
scale = height /
|
|
55
|
+
scale = height / inner.height;
|
|
56
56
|
} else {
|
|
57
57
|
width = outer.height * aspectInner;
|
|
58
58
|
height = outer.height;
|
|
59
59
|
x = outer.width * posX - width * posX;
|
|
60
60
|
y = 0;
|
|
61
|
-
scale = width /
|
|
61
|
+
scale = width / inner.width;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
var rect = {
|