@pyreon/elements 0.11.1 → 0.11.3
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/package.json +8 -7
- package/src/Element/component.tsx +211 -0
- package/src/Element/constants.ts +96 -0
- package/src/Element/index.ts +6 -0
- package/src/Element/types.ts +168 -0
- package/src/Element/utils.ts +15 -0
- package/src/List/component.tsx +57 -0
- package/src/List/index.ts +5 -0
- package/src/Overlay/component.tsx +131 -0
- package/src/Overlay/context.tsx +37 -0
- package/src/Overlay/index.ts +7 -0
- package/src/Overlay/useOverlay.tsx +616 -0
- package/src/Portal/component.tsx +41 -0
- package/src/Portal/index.ts +5 -0
- package/src/Text/component.tsx +65 -0
- package/src/Text/index.ts +5 -0
- package/src/Text/styled.ts +30 -0
- package/src/Util/component.tsx +43 -0
- package/src/Util/index.ts +5 -0
- package/src/__tests__/Content.test.tsx +115 -0
- package/src/__tests__/Element.test.ts +604 -0
- package/src/__tests__/Iterator.test.ts +483 -0
- package/src/__tests__/List.test.ts +199 -0
- package/src/__tests__/Overlay.test.ts +485 -0
- package/src/__tests__/Portal.test.ts +82 -0
- package/src/__tests__/Text.test.ts +274 -0
- package/src/__tests__/Util.test.ts +63 -0
- package/src/__tests__/Wrapper.test.tsx +152 -0
- package/src/__tests__/equalBeforeAfter.test.ts +122 -0
- package/src/__tests__/helpers.test.ts +65 -0
- package/src/__tests__/overlayContext.test.tsx +78 -0
- package/src/__tests__/responsiveProps.test.ts +298 -0
- package/src/__tests__/useOverlay.test.ts +1330 -0
- package/src/__tests__/utils.test.ts +69 -0
- package/src/constants.ts +1 -0
- package/src/helpers/Content/component.tsx +51 -0
- package/src/helpers/Content/index.ts +3 -0
- package/src/helpers/Content/styled.ts +105 -0
- package/src/helpers/Content/types.ts +49 -0
- package/src/helpers/Iterator/component.tsx +252 -0
- package/src/helpers/Iterator/index.ts +13 -0
- package/src/helpers/Iterator/types.ts +79 -0
- package/src/helpers/Wrapper/component.tsx +78 -0
- package/src/helpers/Wrapper/constants.ts +10 -0
- package/src/helpers/Wrapper/index.ts +3 -0
- package/src/helpers/Wrapper/styled.ts +69 -0
- package/src/helpers/Wrapper/types.ts +56 -0
- package/src/helpers/Wrapper/utils.ts +7 -0
- package/src/helpers/index.ts +4 -0
- package/src/index.ts +37 -0
- package/src/types.ts +81 -0
- package/src/utils.ts +1 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { popContext } from "@pyreon/core"
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest"
|
|
3
|
+
import OverlayContextProvider, { useOverlayContext } from "../Overlay/context"
|
|
4
|
+
|
|
5
|
+
describe("Overlay context", () => {
|
|
6
|
+
it("useOverlayContext is a function", () => {
|
|
7
|
+
expect(typeof useOverlayContext).toBe("function")
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
it("returns the default context (empty object) when called outside a provider", () => {
|
|
11
|
+
const ctx = useOverlayContext()
|
|
12
|
+
expect(ctx).toEqual({})
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe("OverlayContextProvider component", () => {
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
try {
|
|
19
|
+
popContext()
|
|
20
|
+
} catch {
|
|
21
|
+
// Ignore if no context was pushed
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it("provides blocked/setBlocked/setUnblocked via context", () => {
|
|
26
|
+
const setBlocked = vi.fn()
|
|
27
|
+
const setUnblocked = vi.fn()
|
|
28
|
+
|
|
29
|
+
OverlayContextProvider({
|
|
30
|
+
blocked: true,
|
|
31
|
+
setBlocked,
|
|
32
|
+
setUnblocked,
|
|
33
|
+
children: "child",
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
const ctx = useOverlayContext()
|
|
37
|
+
expect(ctx.blocked).toBe(true)
|
|
38
|
+
expect(ctx.setBlocked).toBe(setBlocked)
|
|
39
|
+
expect(ctx.setUnblocked).toBe(setUnblocked)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it("renders children (returns a value)", () => {
|
|
43
|
+
const result = OverlayContextProvider({
|
|
44
|
+
blocked: false,
|
|
45
|
+
setBlocked: vi.fn(),
|
|
46
|
+
setUnblocked: vi.fn(),
|
|
47
|
+
children: "Hello overlay",
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
expect(result).toBeDefined()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it("provides blocked as false", () => {
|
|
54
|
+
OverlayContextProvider({
|
|
55
|
+
blocked: false,
|
|
56
|
+
setBlocked: vi.fn(),
|
|
57
|
+
setUnblocked: vi.fn(),
|
|
58
|
+
children: null,
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const ctx = useOverlayContext()
|
|
62
|
+
expect(ctx.blocked).toBe(false)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it("provides blocked as a function when passed as a function", () => {
|
|
66
|
+
const blockedFn = () => true
|
|
67
|
+
|
|
68
|
+
OverlayContextProvider({
|
|
69
|
+
blocked: blockedFn,
|
|
70
|
+
setBlocked: vi.fn(),
|
|
71
|
+
setUnblocked: vi.fn(),
|
|
72
|
+
children: null,
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const ctx = useOverlayContext()
|
|
76
|
+
expect(ctx.blocked).toBe(blockedFn)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import type { VNode } from "@pyreon/core"
|
|
2
|
+
import { h } from "@pyreon/core"
|
|
3
|
+
import { describe, expect, it } from "vitest"
|
|
4
|
+
import { Element } from "../Element"
|
|
5
|
+
import Content from "../helpers/Content/component"
|
|
6
|
+
import Wrapper from "../helpers/Wrapper/component"
|
|
7
|
+
|
|
8
|
+
const asVNode = (v: unknown) => v as VNode
|
|
9
|
+
|
|
10
|
+
const getContentSlots = (result: VNode): VNode[] => {
|
|
11
|
+
const children = result.props.children
|
|
12
|
+
if (!Array.isArray(children)) return []
|
|
13
|
+
return children.filter(
|
|
14
|
+
(c: unknown) =>
|
|
15
|
+
c != null && typeof c === "object" && "type" in (c as VNode) && (c as VNode).type === Content,
|
|
16
|
+
) as VNode[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("Element responsive props", () => {
|
|
20
|
+
describe("single values", () => {
|
|
21
|
+
it("renders with alignX as string", () => {
|
|
22
|
+
const result = asVNode(Element({ alignX: "center", children: "content" }))
|
|
23
|
+
expect(result.type).toBe(Wrapper)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it("renders with alignY as string", () => {
|
|
27
|
+
const result = asVNode(Element({ alignY: "top", children: "content" }))
|
|
28
|
+
expect(result.type).toBe(Wrapper)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it("renders with direction as string", () => {
|
|
32
|
+
const result = asVNode(Element({ direction: "rows", children: "content" }))
|
|
33
|
+
expect(result.type).toBe(Wrapper)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("renders with gap as number", () => {
|
|
37
|
+
const result = asVNode(
|
|
38
|
+
Element({
|
|
39
|
+
gap: 16,
|
|
40
|
+
beforeContent: h("span", null, "Before"),
|
|
41
|
+
afterContent: h("span", null, "After"),
|
|
42
|
+
children: "content",
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
45
|
+
expect(result.type).toBe(Wrapper)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it("renders with block as boolean", () => {
|
|
49
|
+
const result = asVNode(Element({ block: true, children: "content" }))
|
|
50
|
+
expect(result.type).toBe(Wrapper)
|
|
51
|
+
expect(result.props.block).toBe(true)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it("renders with equalCols as boolean", () => {
|
|
55
|
+
const result = asVNode(
|
|
56
|
+
Element({
|
|
57
|
+
equalCols: true,
|
|
58
|
+
beforeContent: h("span", null, "Before"),
|
|
59
|
+
afterContent: h("span", null, "After"),
|
|
60
|
+
children: "content",
|
|
61
|
+
}),
|
|
62
|
+
)
|
|
63
|
+
expect(result.type).toBe(Wrapper)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
describe("array values (positional breakpoints)", () => {
|
|
68
|
+
it("renders with alignX as array", () => {
|
|
69
|
+
const result = asVNode(
|
|
70
|
+
Element({ alignX: ["left", "center", "right"] as any, children: "content" }),
|
|
71
|
+
)
|
|
72
|
+
expect(result.type).toBe(Wrapper)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it("renders with alignY as array", () => {
|
|
76
|
+
const result = asVNode(
|
|
77
|
+
Element({ alignY: ["top", "center", "bottom"] as any, children: "content" }),
|
|
78
|
+
)
|
|
79
|
+
expect(result.type).toBe(Wrapper)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it("renders with direction as array", () => {
|
|
83
|
+
const result = asVNode(Element({ direction: ["rows", "inline"] as any, children: "content" }))
|
|
84
|
+
expect(result.type).toBe(Wrapper)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it("renders with gap as array", () => {
|
|
88
|
+
const result = asVNode(
|
|
89
|
+
Element({
|
|
90
|
+
gap: [8, 16, 24] as any,
|
|
91
|
+
beforeContent: h("span", null, "Before"),
|
|
92
|
+
children: "content",
|
|
93
|
+
}),
|
|
94
|
+
)
|
|
95
|
+
expect(result.type).toBe(Wrapper)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it("renders with block as array", () => {
|
|
99
|
+
const result = asVNode(Element({ block: [false, true] as any, children: "content" }))
|
|
100
|
+
expect(result.type).toBe(Wrapper)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it("renders with equalCols as array", () => {
|
|
104
|
+
const result = asVNode(
|
|
105
|
+
Element({
|
|
106
|
+
equalCols: [false, true] as any,
|
|
107
|
+
beforeContent: h("span", null, "Before"),
|
|
108
|
+
afterContent: h("span", null, "After"),
|
|
109
|
+
children: "content",
|
|
110
|
+
}),
|
|
111
|
+
)
|
|
112
|
+
expect(result.type).toBe(Wrapper)
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
describe("breakpoint object values", () => {
|
|
117
|
+
it("renders with alignX as breakpoint object", () => {
|
|
118
|
+
const result = asVNode(
|
|
119
|
+
Element({
|
|
120
|
+
alignX: { xs: "left", md: "center", xl: "right" } as any,
|
|
121
|
+
children: "content",
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
expect(result.type).toBe(Wrapper)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it("renders with alignY as breakpoint object", () => {
|
|
128
|
+
const result = asVNode(
|
|
129
|
+
Element({ alignY: { xs: "top", lg: "center" } as any, children: "content" }),
|
|
130
|
+
)
|
|
131
|
+
expect(result.type).toBe(Wrapper)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it("renders with direction as breakpoint object", () => {
|
|
135
|
+
const result = asVNode(
|
|
136
|
+
Element({
|
|
137
|
+
direction: { xs: "rows", md: "inline" } as any,
|
|
138
|
+
children: "content",
|
|
139
|
+
}),
|
|
140
|
+
)
|
|
141
|
+
expect(result.type).toBe(Wrapper)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it("renders with gap as breakpoint object", () => {
|
|
145
|
+
const result = asVNode(
|
|
146
|
+
Element({
|
|
147
|
+
gap: { xs: 8, md: 16, lg: 24 } as any,
|
|
148
|
+
beforeContent: h("span", null, "Before"),
|
|
149
|
+
children: "content",
|
|
150
|
+
}),
|
|
151
|
+
)
|
|
152
|
+
expect(result.type).toBe(Wrapper)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it("renders with block as breakpoint object", () => {
|
|
156
|
+
const result = asVNode(
|
|
157
|
+
Element({ block: { xs: false, md: true } as any, children: "content" }),
|
|
158
|
+
)
|
|
159
|
+
expect(result.type).toBe(Wrapper)
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
describe("combined responsive props", () => {
|
|
164
|
+
it("renders with multiple responsive props simultaneously", () => {
|
|
165
|
+
const result = asVNode(
|
|
166
|
+
Element({
|
|
167
|
+
alignX: { xs: "left", md: "center" } as any,
|
|
168
|
+
alignY: ["top", "center"] as any,
|
|
169
|
+
direction: { xs: "rows", lg: "inline" } as any,
|
|
170
|
+
block: [false, true] as any,
|
|
171
|
+
gap: 16,
|
|
172
|
+
beforeContent: h("span", { "data-testid": "before" }, "Before"),
|
|
173
|
+
afterContent: h("span", { "data-testid": "after" }, "After"),
|
|
174
|
+
children: h("span", { "data-testid": "main" }, "Main"),
|
|
175
|
+
}),
|
|
176
|
+
)
|
|
177
|
+
expect(result.type).toBe(Wrapper)
|
|
178
|
+
const slots = getContentSlots(result)
|
|
179
|
+
expect(slots).toHaveLength(3)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it("renders with responsive content directions", () => {
|
|
183
|
+
const result = asVNode(
|
|
184
|
+
Element({
|
|
185
|
+
contentDirection: { xs: "rows", md: "inline" } as any,
|
|
186
|
+
beforeContentDirection: { xs: "inline", lg: "rows" } as any,
|
|
187
|
+
afterContentDirection: "inline",
|
|
188
|
+
beforeContent: h("span", null, "Before"),
|
|
189
|
+
afterContent: h("span", null, "After"),
|
|
190
|
+
children: h("span", null, "Main"),
|
|
191
|
+
}),
|
|
192
|
+
)
|
|
193
|
+
expect(result.type).toBe(Wrapper)
|
|
194
|
+
const slots = getContentSlots(result)
|
|
195
|
+
expect(slots).toHaveLength(3)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it("renders with responsive content alignment", () => {
|
|
199
|
+
const result = asVNode(
|
|
200
|
+
Element({
|
|
201
|
+
contentAlignX: { xs: "left", md: "center" } as any,
|
|
202
|
+
contentAlignY: ["top", "center", "bottom"] as any,
|
|
203
|
+
beforeContentAlignX: "left",
|
|
204
|
+
afterContentAlignX: "right",
|
|
205
|
+
beforeContent: h("span", null, "Before"),
|
|
206
|
+
afterContent: h("span", null, "After"),
|
|
207
|
+
children: "content",
|
|
208
|
+
}),
|
|
209
|
+
)
|
|
210
|
+
expect(result.type).toBe(Wrapper)
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
describe("responsive css prop", () => {
|
|
215
|
+
it("renders with css as string", () => {
|
|
216
|
+
const result = asVNode(Element({ css: "background: red;", children: "content" }))
|
|
217
|
+
expect(result.type).toBe(Wrapper)
|
|
218
|
+
expect(result.props.extendCss).toBe("background: red;")
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it("renders with contentCss", () => {
|
|
222
|
+
const result = asVNode(
|
|
223
|
+
Element({
|
|
224
|
+
contentCss: "color: blue;",
|
|
225
|
+
beforeContent: h("span", null, "Before"),
|
|
226
|
+
children: "content",
|
|
227
|
+
}),
|
|
228
|
+
)
|
|
229
|
+
expect(result.type).toBe(Wrapper)
|
|
230
|
+
const slots = getContentSlots(result)
|
|
231
|
+
const contentSlot = slots.find((v) => v.props.contentType === "content")
|
|
232
|
+
expect(contentSlot?.props.extendCss).toBe("color: blue;")
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
it("renders with beforeContentCss and afterContentCss", () => {
|
|
236
|
+
const result = asVNode(
|
|
237
|
+
Element({
|
|
238
|
+
beforeContentCss: "padding: 4px;",
|
|
239
|
+
afterContentCss: "padding: 8px;",
|
|
240
|
+
beforeContent: h("span", null, "Before"),
|
|
241
|
+
afterContent: h("span", null, "After"),
|
|
242
|
+
children: "content",
|
|
243
|
+
}),
|
|
244
|
+
)
|
|
245
|
+
expect(result.type).toBe(Wrapper)
|
|
246
|
+
const slots = getContentSlots(result)
|
|
247
|
+
const beforeSlot = slots.find((v) => v.props.contentType === "before")
|
|
248
|
+
const afterSlot = slots.find((v) => v.props.contentType === "after")
|
|
249
|
+
expect(beforeSlot?.props.extendCss).toBe("padding: 4px;")
|
|
250
|
+
expect(afterSlot?.props.extendCss).toBe("padding: 8px;")
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
describe("alignment values", () => {
|
|
255
|
+
const alignXValues = [
|
|
256
|
+
"left",
|
|
257
|
+
"center",
|
|
258
|
+
"right",
|
|
259
|
+
"spaceBetween",
|
|
260
|
+
"spaceAround",
|
|
261
|
+
"block",
|
|
262
|
+
] as const
|
|
263
|
+
|
|
264
|
+
const alignYValues = [
|
|
265
|
+
"top",
|
|
266
|
+
"center",
|
|
267
|
+
"bottom",
|
|
268
|
+
"spaceBetween",
|
|
269
|
+
"spaceAround",
|
|
270
|
+
"block",
|
|
271
|
+
] as const
|
|
272
|
+
|
|
273
|
+
for (const value of alignXValues) {
|
|
274
|
+
it(`renders with alignX="${value}"`, () => {
|
|
275
|
+
const result = asVNode(Element({ alignX: value, children: "content" }))
|
|
276
|
+
expect(result.type).toBe(Wrapper)
|
|
277
|
+
})
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
for (const value of alignYValues) {
|
|
281
|
+
it(`renders with alignY="${value}"`, () => {
|
|
282
|
+
const result = asVNode(Element({ alignY: value, children: "content" }))
|
|
283
|
+
expect(result.type).toBe(Wrapper)
|
|
284
|
+
})
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
describe("direction values", () => {
|
|
289
|
+
const directionValues = ["inline", "rows", "reverseInline", "reverseRows"] as const
|
|
290
|
+
|
|
291
|
+
for (const value of directionValues) {
|
|
292
|
+
it(`renders with direction="${value}"`, () => {
|
|
293
|
+
const result = asVNode(Element({ direction: value, children: "content" }))
|
|
294
|
+
expect(result.type).toBe(Wrapper)
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
})
|
|
298
|
+
})
|