@pyreon/elements 0.24.5 → 0.25.0

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 (71) hide show
  1. package/lib/index.js +5 -1
  2. package/package.json +11 -13
  3. package/src/Element/component.tsx +0 -315
  4. package/src/Element/constants.ts +0 -96
  5. package/src/Element/index.ts +0 -6
  6. package/src/Element/types.ts +0 -168
  7. package/src/Element/utils.ts +0 -15
  8. package/src/List/component.tsx +0 -105
  9. package/src/List/index.ts +0 -5
  10. package/src/Overlay/component.tsx +0 -140
  11. package/src/Overlay/context.tsx +0 -36
  12. package/src/Overlay/index.ts +0 -7
  13. package/src/Overlay/positioning.ts +0 -191
  14. package/src/Overlay/useOverlay.tsx +0 -461
  15. package/src/Portal/component.tsx +0 -54
  16. package/src/Portal/index.ts +0 -5
  17. package/src/Text/component.tsx +0 -67
  18. package/src/Text/index.ts +0 -5
  19. package/src/Text/styled.ts +0 -30
  20. package/src/Util/component.tsx +0 -43
  21. package/src/Util/index.ts +0 -5
  22. package/src/__tests__/Content.test.tsx +0 -123
  23. package/src/__tests__/Element-slot-reactivity.browser.test.tsx +0 -152
  24. package/src/__tests__/Element.test.ts +0 -819
  25. package/src/__tests__/Iterator.test.ts +0 -492
  26. package/src/__tests__/Iterator.types.test.ts +0 -237
  27. package/src/__tests__/List.test.ts +0 -199
  28. package/src/__tests__/Overlay.test.ts +0 -492
  29. package/src/__tests__/Portal.test.ts +0 -156
  30. package/src/__tests__/Text.test.ts +0 -274
  31. package/src/__tests__/Util.test.ts +0 -63
  32. package/src/__tests__/Wrapper-innerhtml.test.tsx +0 -178
  33. package/src/__tests__/Wrapper.test.tsx +0 -196
  34. package/src/__tests__/elements.browser.test.tsx +0 -132
  35. package/src/__tests__/equalBeforeAfter.test.ts +0 -122
  36. package/src/__tests__/helpers.test.ts +0 -65
  37. package/src/__tests__/integration.test.tsx +0 -118
  38. package/src/__tests__/internElementBundle.test.ts +0 -102
  39. package/src/__tests__/iterator-function-children.test.tsx +0 -120
  40. package/src/__tests__/native-markers.test.ts +0 -13
  41. package/src/__tests__/overlayContext.test.tsx +0 -78
  42. package/src/__tests__/perf-stress.browser.test.tsx +0 -119
  43. package/src/__tests__/positioning.test.ts +0 -90
  44. package/src/__tests__/responsiveProps.test.ts +0 -328
  45. package/src/__tests__/slot-component-reference.test.tsx +0 -157
  46. package/src/__tests__/useOverlay.test.ts +0 -1336
  47. package/src/__tests__/utils.test.ts +0 -69
  48. package/src/__tests__/wrapper-block-cascade.test.ts +0 -121
  49. package/src/constants.ts +0 -1
  50. package/src/env.d.ts +0 -6
  51. package/src/helpers/Content/component.tsx +0 -75
  52. package/src/helpers/Content/index.ts +0 -3
  53. package/src/helpers/Content/styled.ts +0 -105
  54. package/src/helpers/Content/types.ts +0 -49
  55. package/src/helpers/Iterator/component.tsx +0 -316
  56. package/src/helpers/Iterator/index.ts +0 -30
  57. package/src/helpers/Iterator/types.ts +0 -138
  58. package/src/helpers/Wrapper/component.tsx +0 -180
  59. package/src/helpers/Wrapper/constants.ts +0 -10
  60. package/src/helpers/Wrapper/index.ts +0 -3
  61. package/src/helpers/Wrapper/styled.ts +0 -64
  62. package/src/helpers/Wrapper/types.ts +0 -56
  63. package/src/helpers/Wrapper/utils.ts +0 -7
  64. package/src/helpers/index.ts +0 -4
  65. package/src/helpers/internElementBundle.ts +0 -37
  66. package/src/helpers/isPyreonComponent.ts +0 -46
  67. package/src/index.ts +0 -42
  68. package/src/manifest.ts +0 -190
  69. package/src/tests/manifest-snapshot.test.ts +0 -45
  70. package/src/types.ts +0 -112
  71. package/src/utils.ts +0 -5
@@ -1,69 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { getShouldBeEmpty, isInlineElement } from '../Element/utils'
3
- import { isWebFixNeeded } from '../helpers/Wrapper/utils'
4
-
5
- describe('isInlineElement', () => {
6
- it('returns true for inline elements', () => {
7
- expect(isInlineElement('span')).toBe(true)
8
- expect(isInlineElement('a')).toBe(true)
9
- expect(isInlineElement('button')).toBe(true)
10
- expect(isInlineElement('input')).toBe(true)
11
- expect(isInlineElement('label')).toBe(true)
12
- expect(isInlineElement('strong')).toBe(true)
13
- expect(isInlineElement('em')).toBe(true)
14
- expect(isInlineElement('img')).toBe(true)
15
- })
16
-
17
- it('returns false for block elements', () => {
18
- expect(isInlineElement('div')).toBe(false)
19
- expect(isInlineElement('p')).toBe(false)
20
- expect(isInlineElement('section')).toBe(false)
21
- expect(isInlineElement('header')).toBe(false)
22
- })
23
-
24
- it('returns false for undefined', () => {
25
- expect(isInlineElement(undefined)).toBe(false)
26
- })
27
-
28
- it('returns false for empty string', () => {
29
- expect(isInlineElement('')).toBe(false)
30
- })
31
- })
32
-
33
- describe('getShouldBeEmpty', () => {
34
- it('returns true for void elements', () => {
35
- expect(getShouldBeEmpty('br')).toBe(true)
36
- expect(getShouldBeEmpty('img')).toBe(true)
37
- expect(getShouldBeEmpty('input')).toBe(true)
38
- expect(getShouldBeEmpty('hr')).toBe(true)
39
- expect(getShouldBeEmpty('embed')).toBe(true)
40
- })
41
-
42
- it('returns false for non-void elements', () => {
43
- expect(getShouldBeEmpty('div')).toBe(false)
44
- expect(getShouldBeEmpty('span')).toBe(false)
45
- expect(getShouldBeEmpty('p')).toBe(false)
46
- })
47
-
48
- it('returns false for undefined', () => {
49
- expect(getShouldBeEmpty(undefined)).toBe(false)
50
- })
51
- })
52
-
53
- describe('isWebFixNeeded', () => {
54
- it('returns true for button, fieldset, legend', () => {
55
- expect(isWebFixNeeded('button')).toBe(true)
56
- expect(isWebFixNeeded('fieldset')).toBe(true)
57
- expect(isWebFixNeeded('legend')).toBe(true)
58
- })
59
-
60
- it('returns false for other elements', () => {
61
- expect(isWebFixNeeded('div')).toBe(false)
62
- expect(isWebFixNeeded('span')).toBe(false)
63
- expect(isWebFixNeeded('input')).toBe(false)
64
- })
65
-
66
- it('returns false for undefined', () => {
67
- expect(isWebFixNeeded(undefined)).toBe(false)
68
- })
69
- })
@@ -1,121 +0,0 @@
1
- import { describe, expect, it } from 'vitest'
2
- import { styles } from '../helpers/Wrapper/styled'
3
-
4
- /**
5
- * Regression test for the responsive `block` cascade bug (mirrors vitus-labs's
6
- * "couple of fixes" PR #121).
7
- *
8
- * Scenario: a responsive theme like `block: [true, false, true]` runs the
9
- * styles callback once per breakpoint with a single-value `t.block`. The bug
10
- * was that `align-self`, `flex`/`width` etc. were emitted ONLY when
11
- * `t.block` was truthy — so the breakpoint where `t.block` is false emitted
12
- * nothing, leaving the previous breakpoint's `align-self: stretch` cascading
13
- * through the mobile-first @media query.
14
- *
15
- * Fix: always emit a value for these properties (truthy → stretch/100%,
16
- * falsy → auto/auto). The mobile-first @media cascade then resets cleanly
17
- * when `block` flips false at a later breakpoint.
18
- *
19
- * The styles callback is called per-breakpoint with the per-breakpoint theme
20
- * already resolved to a single value — so testing it directly with two
21
- * scalar themes is enough to lock in the always-emit contract.
22
- */
23
-
24
- const identityCss = (strings: TemplateStringsArray, ...vals: unknown[]) => {
25
- let r = ''
26
- for (let i = 0; i < strings.length; i++) {
27
- r += strings[i]
28
- if (i < vals.length) {
29
- const v = vals[i]
30
- // Mirror styled-components / styler interpolation: drop falsy
31
- // interpolations, stringify the rest. CSSResult instances (from the
32
- // alignContent / extendCss helpers) coerce via their toString.
33
- if (v === false || v == null) continue
34
- r += String(v)
35
- }
36
- }
37
- return r
38
- }
39
-
40
- const renderAt = (theme: Record<string, unknown>): string =>
41
- String(styles({ theme, css: identityCss }))
42
-
43
- describe('Wrapper styles — responsive block cascade reset', () => {
44
- it('emits stretch/100%/flex when block is true', () => {
45
- const out = renderAt({
46
- block: true,
47
- direction: 'inline',
48
- alignX: 'left',
49
- alignY: 'center',
50
- })
51
- expect(out).toContain('align-self: stretch')
52
- expect(out).toContain('width: 100%')
53
- expect(out).toContain('display: flex')
54
- })
55
-
56
- it('emits auto/auto/inline-flex reset when block is false (key fix)', () => {
57
- const out = renderAt({
58
- block: false,
59
- direction: 'inline',
60
- alignX: 'left',
61
- alignY: 'center',
62
- })
63
- // The fix: these properties MUST be emitted with reset values so the
64
- // mobile-first @media cascade doesn't leak `align-self: stretch` from a
65
- // smaller breakpoint where block was true.
66
- expect(out).toContain('align-self: auto')
67
- expect(out).toContain('width: auto')
68
- expect(out).toContain('display: inline-flex')
69
- })
70
-
71
- it('emits height: 100% when alignY is "block", auto otherwise', () => {
72
- const blockY = renderAt({
73
- block: false,
74
- direction: 'inline',
75
- alignX: 'left',
76
- alignY: 'block',
77
- })
78
- expect(blockY).toContain('height: 100%')
79
-
80
- const nonBlockY = renderAt({
81
- block: false,
82
- direction: 'inline',
83
- alignX: 'left',
84
- alignY: 'center',
85
- })
86
- expect(nonBlockY).toContain('height: auto')
87
- })
88
-
89
- it('does not emit display when childFix is set (parent split)', () => {
90
- const out = renderAt({
91
- block: true,
92
- childFix: true,
93
- direction: 'inline',
94
- alignX: 'left',
95
- alignY: 'center',
96
- })
97
- // childFix branch handles its own display rules outside the responsive
98
- // styles callback.
99
- expect(out).not.toContain('display: flex;')
100
- expect(out).not.toContain('display: inline-flex;')
101
- })
102
-
103
- it('emits parentFix flex-direction: column only when parentFix is set', () => {
104
- const withParentFix = renderAt({
105
- block: true,
106
- parentFix: true,
107
- direction: 'inline',
108
- alignX: 'left',
109
- alignY: 'center',
110
- })
111
- expect(withParentFix).toContain('flex-direction: column')
112
-
113
- const withoutParentFix = renderAt({
114
- block: true,
115
- direction: 'inline',
116
- alignX: 'left',
117
- alignY: 'center',
118
- })
119
- expect(withoutParentFix).not.toContain('flex-direction: column')
120
- })
121
- })
package/src/constants.ts DELETED
@@ -1 +0,0 @@
1
- export const PKG_NAME = '@pyreon/elements' as const
package/src/env.d.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Minimal process type — just enough for `process.env.NODE_ENV` checks.
3
- * Avoids requiring @types/node in consumers that import pyreon source
4
- * via the `"bun"` export condition.
5
- */
6
- declare var process: { env: { NODE_ENV?: string } }
@@ -1,75 +0,0 @@
1
- /**
2
- * Content area used inside Element to render one of the three
3
- * layout slots (before, content, after). Passes alignment, direction,
4
- * gap, and equalCols styling props to the underlying styled component.
5
- * Adds a `data-pyr-element` attribute in development for debugging.
6
- *
7
- * Children are rendered via core `render()`, with function-valued
8
- * children unwrapped inside a reactive accessor so the compound-layout
9
- * paths in `Element` keep `content={() => <X />}` reactivity intact
10
- * (mirrors the `resolveSlot` helper in `Element/component.tsx`).
11
- */
12
- import { h, splitProps } from '@pyreon/core'
13
- import type { ComponentFn, VNodeChildAtom } from '@pyreon/core'
14
- import { render } from '@pyreon/ui-core'
15
- import { IS_DEVELOPMENT } from '../../utils'
16
- import { isPyreonComponent } from '../isPyreonComponent'
17
- import Styled from './styled'
18
- import type { Props } from './types'
19
-
20
- // Return type is the RESOLVED atom — see the matching helper in
21
- // Element/component.tsx for the rationale (keeps `() => resolveSlot(...)`
22
- // a valid VNodeChildAccessor at the JSX child position).
23
- //
24
- // Component vs accessor discriminator — see `isPyreonComponent` JSDoc.
25
- // Without this, `beforeContent={Component}` shorthand crashes downstream
26
- // in rocketstyle's `removeUndefinedProps(undefined)`.
27
- const resolveSlot = (value: unknown): VNodeChildAtom | VNodeChildAtom[] => {
28
- if (typeof value === 'function') {
29
- if (isPyreonComponent(value)) {
30
- return h(value as ComponentFn, null) as VNodeChildAtom
31
- }
32
- return (value as () => VNodeChildAtom | VNodeChildAtom[])()
33
- }
34
- return render(value as Parameters<typeof render>[0]) as VNodeChildAtom | VNodeChildAtom[]
35
- }
36
-
37
- const Component = (props: Partial<Props>) => {
38
- const [own, rest] = splitProps(props, [
39
- 'contentType',
40
- 'tag',
41
- 'parentDirection',
42
- 'direction',
43
- 'alignX',
44
- 'alignY',
45
- 'equalCols',
46
- 'gap',
47
- 'extendCss',
48
- 'children',
49
- ])
50
-
51
- const debugProps = IS_DEVELOPMENT
52
- ? {
53
- 'data-pyr-element': own.contentType,
54
- }
55
- : {}
56
-
57
- const stylingProps = {
58
- contentType: own.contentType,
59
- parentDirection: own.parentDirection,
60
- direction: own.direction,
61
- alignX: own.alignX,
62
- alignY: own.alignY,
63
- equalCols: own.equalCols,
64
- gap: own.gap,
65
- extraStyles: own.extendCss,
66
- }
67
-
68
- return (
69
- <Styled as={own.tag} $contentType={own.contentType} $element={stylingProps} {...debugProps} {...rest}>
70
- {() => resolveSlot(own.children)}
71
- </Styled>
72
- )
73
- }
74
-
75
- export default Component
@@ -1,3 +0,0 @@
1
- import component from './component'
2
-
3
- export default component
@@ -1,105 +0,0 @@
1
- /**
2
- * Styled component for content areas (before/content/after). Applies
3
- * responsive flex alignment, gap spacing between slots based on parent
4
- * direction (margin-right for inline, margin-bottom for rows), and
5
- * equalCols flex distribution. The "content" slot gets `flex: 1` to
6
- * fill remaining space between before and after.
7
- */
8
- import { config } from '@pyreon/ui-core'
9
- import { alignContent, extendCss, makeItResponsive, value } from '@pyreon/unistyle'
10
- import type { ResponsiveStylesCallback } from '../../types'
11
- import type { StyledProps, ThemeProps } from './types'
12
-
13
- const { styled, css, component } = config
14
-
15
- const equalColsCSS = `
16
- flex: 1;
17
- `
18
-
19
- const typeContentCSS = `
20
- flex: 1;
21
- `
22
-
23
- // --------------------------------------------------------
24
- // calculate spacing between before / content / after
25
- // --------------------------------------------------------
26
- const gapDimensions = {
27
- inline: {
28
- before: 'margin-right',
29
- after: 'margin-left',
30
- },
31
- reverseInline: {
32
- before: 'margin-right',
33
- after: 'margin-left',
34
- },
35
- rows: {
36
- before: 'margin-bottom',
37
- after: 'margin-top',
38
- },
39
- reverseRows: {
40
- before: 'margin-bottom',
41
- after: 'margin-top',
42
- },
43
- } as const
44
-
45
- const calculateGap = ({
46
- direction,
47
- type,
48
- value: gapValue,
49
- }: {
50
- direction: keyof typeof gapDimensions
51
- type: ThemeProps['contentType']
52
- value: string | number | null | undefined
53
- }) => {
54
- if (!direction || !type || type === 'content') return undefined
55
-
56
- const finalStyles = `${gapDimensions[direction][type]}: ${gapValue};`
57
-
58
- return finalStyles
59
- }
60
-
61
- // --------------------------------------------------------
62
- // calculations of styles to be rendered
63
- // --------------------------------------------------------
64
- const styles: ResponsiveStylesCallback = ({ css: cssFn, theme: t, rootSize }) => cssFn`
65
- ${alignContent({
66
- direction: t.direction,
67
- alignX: t.alignX,
68
- alignY: t.alignY,
69
- })};
70
-
71
- ${t.equalCols && equalColsCSS};
72
-
73
- ${
74
- t.gap &&
75
- t.contentType &&
76
- calculateGap({
77
- direction: t.parentDirection,
78
- type: t.contentType,
79
- value: value(t.gap, rootSize),
80
- })
81
- };
82
-
83
- ${t.extraStyles && extendCss(t.extraStyles as Parameters<typeof extendCss>[0])};
84
- `
85
-
86
- const platformCSS = `box-sizing: border-box;`
87
-
88
- const StyledComponent = styled(component, { layer: 'elements' })`
89
- ${platformCSS};
90
-
91
- display: flex;
92
- align-self: stretch;
93
- flex-wrap: wrap;
94
-
95
- ${(({ $contentType }: StyledProps) => $contentType === 'content' && typeContentCSS) as any};
96
-
97
- ${makeItResponsive({
98
- key: '$element',
99
- styles,
100
- css,
101
- normalize: true,
102
- })};
103
- `
104
-
105
- export default StyledComponent
@@ -1,49 +0,0 @@
1
- import type { HTMLTags } from '@pyreon/ui-core'
2
- import type {
3
- AlignX,
4
- AlignY,
5
- Content,
6
- ContentAlignX,
7
- ContentAlignY,
8
- ContentBoolean,
9
- ContentDirection,
10
- ContentSimpleValue,
11
- Css,
12
- Direction,
13
- ExtendCss,
14
- Responsive,
15
- ResponsiveBoolType,
16
- } from '../../types'
17
-
18
- export interface Props {
19
- parentDirection: Direction | undefined
20
- gap: Responsive | undefined
21
- contentType: 'before' | 'content' | 'after' | undefined
22
- children: Content
23
- tag: HTMLTags | undefined
24
- direction: Direction | undefined
25
- alignX: AlignX | undefined
26
- alignY: AlignY | undefined
27
- equalCols: ResponsiveBoolType | undefined
28
- extendCss: ExtendCss | undefined
29
- }
30
-
31
- export interface StyledProps {
32
- $element: Pick<
33
- Props,
34
- 'contentType' | 'parentDirection' | 'direction' | 'alignX' | 'alignY' | 'equalCols' | 'gap'
35
- > & {
36
- extraStyles: Props['extendCss']
37
- }
38
- $contentType: Props['contentType']
39
- }
40
-
41
- export type ThemeProps = Pick<Props, 'contentType'> & {
42
- parentDirection: ContentDirection
43
- direction: ContentDirection
44
- alignX: ContentAlignX
45
- alignY: ContentAlignY
46
- equalCols?: ContentBoolean
47
- gap?: ContentSimpleValue
48
- extraStyles?: Css
49
- }