@pyreon/ui-core 0.24.5 → 0.24.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/package.json +7 -9
- package/src/PyreonUI.tsx +0 -227
- package/src/__tests__/PyreonUI-inheritance.test.tsx +0 -157
- package/src/__tests__/PyreonUI.test.tsx +0 -194
- package/src/__tests__/compose.test.ts +0 -32
- package/src/__tests__/config.test.ts +0 -102
- package/src/__tests__/context.test.tsx +0 -71
- package/src/__tests__/hoistNonReactStatics.test.tsx +0 -166
- package/src/__tests__/isEmpty.test.ts +0 -53
- package/src/__tests__/isEqual.test.ts +0 -114
- package/src/__tests__/manifest-snapshot.test.ts +0 -27
- package/src/__tests__/native-markers.test.ts +0 -13
- package/src/__tests__/render.test.tsx +0 -72
- package/src/__tests__/useStableValue.test.ts +0 -118
- package/src/__tests__/utils.test.ts +0 -537
- package/src/compose.ts +0 -11
- package/src/config.ts +0 -57
- package/src/context.tsx +0 -80
- package/src/hoistNonReactStatics.ts +0 -59
- package/src/html/htmlElementAttrs.ts +0 -106
- package/src/html/htmlTags.ts +0 -151
- package/src/html/index.ts +0 -11
- package/src/index.ts +0 -57
- package/src/isEmpty.ts +0 -20
- package/src/isEqual.ts +0 -27
- package/src/manifest.ts +0 -104
- package/src/render.tsx +0 -50
- package/src/types.ts +0 -5
- package/src/useStableValue.ts +0 -21
- package/src/utils.ts +0 -187
package/src/config.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { StyledFunction } from '@pyreon/styler'
|
|
2
|
-
import { css, keyframes, styled } from '@pyreon/styler'
|
|
3
|
-
import type { HTMLTags } from './html'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Describes the shape of the CSS-in-JS engine.
|
|
7
|
-
* Pyreon uses @pyreon/styler directly — no connector abstraction needed.
|
|
8
|
-
* This type is kept for API compatibility with downstream packages.
|
|
9
|
-
*/
|
|
10
|
-
export interface CSSEngineConnector {
|
|
11
|
-
css: typeof css
|
|
12
|
-
styled: typeof styled
|
|
13
|
-
keyframes: typeof keyframes
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface PlatformConfig {
|
|
17
|
-
component: string | HTMLTags
|
|
18
|
-
textComponent: string | HTMLTags
|
|
19
|
-
createMediaQueries?: (props: {
|
|
20
|
-
breakpoints: Record<string, number>
|
|
21
|
-
rootSize: number
|
|
22
|
-
css: CSSEngineConnector['css']
|
|
23
|
-
}) => Record<string, (...args: any[]) => any>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
type InitConfig = Partial<CSSEngineConnector & PlatformConfig>
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Configuration singleton that bridges the UI system with the CSS engine.
|
|
30
|
-
* All packages reference config.css, config.styled, etc.
|
|
31
|
-
*
|
|
32
|
-
* In Pyreon, the engine is @pyreon/styler and is available immediately —
|
|
33
|
-
* no lazy initialization or connector pattern needed.
|
|
34
|
-
*/
|
|
35
|
-
class Configuration {
|
|
36
|
-
css = css
|
|
37
|
-
styled: StyledFunction = styled
|
|
38
|
-
keyframes = keyframes
|
|
39
|
-
component: string | HTMLTags = 'div'
|
|
40
|
-
textComponent: string | HTMLTags = 'span'
|
|
41
|
-
createMediaQueries: PlatformConfig['createMediaQueries'] = undefined
|
|
42
|
-
|
|
43
|
-
init = (props: InitConfig) => {
|
|
44
|
-
if (props.css) this.css = props.css
|
|
45
|
-
if (props.styled) this.styled = props.styled
|
|
46
|
-
if (props.keyframes) this.keyframes = props.keyframes
|
|
47
|
-
if (props.component) this.component = props.component
|
|
48
|
-
if (props.textComponent) this.textComponent = props.textComponent
|
|
49
|
-
if (props.createMediaQueries) this.createMediaQueries = props.createMediaQueries
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const config = new Configuration()
|
|
54
|
-
const { init } = config
|
|
55
|
-
|
|
56
|
-
export default config
|
|
57
|
-
export { init }
|
package/src/context.tsx
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import type { VNodeChild } from '@pyreon/core'
|
|
2
|
-
import { createReactiveContext, nativeCompat, provide } from '@pyreon/core'
|
|
3
|
-
import isEmpty from './isEmpty'
|
|
4
|
-
import type { Breakpoints } from './types'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Core context value shared across all @pyreon UI packages.
|
|
8
|
-
*/
|
|
9
|
-
export interface CoreContextValue {
|
|
10
|
-
theme: Record<string, unknown>
|
|
11
|
-
mode: 'light' | 'dark'
|
|
12
|
-
isDark: boolean
|
|
13
|
-
isLight: boolean
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Internal reactive context shared across all @pyreon packages.
|
|
18
|
-
* Carries the theme object, mode, and derived dark/light flags.
|
|
19
|
-
*
|
|
20
|
-
* ReactiveContext means useContext() returns `() => CoreContextValue`.
|
|
21
|
-
*/
|
|
22
|
-
const context = createReactiveContext<CoreContextValue>({
|
|
23
|
-
theme: {},
|
|
24
|
-
mode: 'light',
|
|
25
|
-
isDark: false,
|
|
26
|
-
isLight: true,
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
type Theme = Partial<
|
|
30
|
-
{
|
|
31
|
-
rootSize: number
|
|
32
|
-
breakpoints: Breakpoints
|
|
33
|
-
} & Record<string, any>
|
|
34
|
-
>
|
|
35
|
-
|
|
36
|
-
type ProviderType = Partial<
|
|
37
|
-
{
|
|
38
|
-
theme: Theme
|
|
39
|
-
children: VNodeChild
|
|
40
|
-
} & Record<string, any>
|
|
41
|
-
>
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @internal Low-level provider — use `PyreonUI` from `@pyreon/ui-core` instead.
|
|
45
|
-
*
|
|
46
|
-
* Provider that feeds the internal Pyreon context with the theme.
|
|
47
|
-
* When no theme is supplied, renders children directly.
|
|
48
|
-
*
|
|
49
|
-
* @deprecated Prefer `<PyreonUI theme={theme}>` which handles all context layers.
|
|
50
|
-
*/
|
|
51
|
-
function Provider({ theme, children, ...props }: ProviderType): VNodeChild {
|
|
52
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
53
|
-
// oxlint-disable-next-line no-console
|
|
54
|
-
console.warn(
|
|
55
|
-
'[Pyreon] CoreProvider is internal. Use <PyreonUI theme={theme}> instead — it handles all context layers (styler, core, mode) in one component.',
|
|
56
|
-
)
|
|
57
|
-
}
|
|
58
|
-
if (isEmpty(theme) || !theme) return children ?? null
|
|
59
|
-
|
|
60
|
-
provide(context, () => ({
|
|
61
|
-
theme: theme as Record<string, unknown>,
|
|
62
|
-
mode: (props.mode as 'light' | 'dark') ?? 'light',
|
|
63
|
-
isDark: props.isDark as boolean ?? false,
|
|
64
|
-
isLight: props.isLight as boolean ?? true,
|
|
65
|
-
...props,
|
|
66
|
-
}))
|
|
67
|
-
|
|
68
|
-
return children ?? null
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Mark as native — even though @internal, PyreonUI invokes this internally
|
|
72
|
-
// AND the JSX inside PyreonUI's body still routes through the active jsx()
|
|
73
|
-
// runtime (which is the compat one in compat-mode apps). Without the marker,
|
|
74
|
-
// CoreProvider's body runs inside the compat wrapper's runUntracked and its
|
|
75
|
-
// provide() call is swallowed.
|
|
76
|
-
nativeCompat(Provider)
|
|
77
|
-
|
|
78
|
-
export { context }
|
|
79
|
-
|
|
80
|
-
export default Provider
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
const KNOWN_STATICS: Record<string, true> = {
|
|
2
|
-
name: true,
|
|
3
|
-
length: true,
|
|
4
|
-
prototype: true,
|
|
5
|
-
caller: true,
|
|
6
|
-
callee: true,
|
|
7
|
-
arguments: true,
|
|
8
|
-
arity: true,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const COMPONENT_STATICS: Record<string, true> = {
|
|
12
|
-
displayName: true,
|
|
13
|
-
defaultProps: true,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Copies non-framework static properties from a source component to a target.
|
|
18
|
-
*
|
|
19
|
-
* Pyreon equivalent of hoistNonReactStatics — simplified since Pyreon
|
|
20
|
-
* components are plain functions without React-specific statics like
|
|
21
|
-
* contextType, propTypes, getDerivedStateFromProps, etc.
|
|
22
|
-
*/
|
|
23
|
-
const hoistNonReactStatics = <T, S>(
|
|
24
|
-
target: T,
|
|
25
|
-
source: S,
|
|
26
|
-
excludeList?: Record<string, true>,
|
|
27
|
-
): T => {
|
|
28
|
-
if (typeof source === 'string') return target
|
|
29
|
-
|
|
30
|
-
const proto = Object.getPrototypeOf(source)
|
|
31
|
-
if (proto && proto !== Object.prototype) {
|
|
32
|
-
hoistNonReactStatics(target, proto, excludeList)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const keys: (string | symbol)[] = [
|
|
36
|
-
...Object.getOwnPropertyNames(source),
|
|
37
|
-
...Object.getOwnPropertySymbols(source),
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
for (const key of keys) {
|
|
41
|
-
const k = key as string
|
|
42
|
-
if (KNOWN_STATICS[k] || excludeList?.[k] || COMPONENT_STATICS[k]) {
|
|
43
|
-
continue
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const descriptor = Object.getOwnPropertyDescriptor(source, key)
|
|
47
|
-
if (descriptor) {
|
|
48
|
-
try {
|
|
49
|
-
Object.defineProperty(target, key, descriptor)
|
|
50
|
-
} catch {
|
|
51
|
-
// Silently skip non-configurable properties
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return target
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export default hoistNonReactStatics
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
type Base = HTMLElement
|
|
2
|
-
|
|
3
|
-
export interface HTMLElementAttrs {
|
|
4
|
-
a: HTMLAnchorElement
|
|
5
|
-
abbr: Base
|
|
6
|
-
address: Base
|
|
7
|
-
area: HTMLAreaElement
|
|
8
|
-
article: Base
|
|
9
|
-
aside: Base
|
|
10
|
-
audio: HTMLAudioElement
|
|
11
|
-
b: Base
|
|
12
|
-
bdi: Base
|
|
13
|
-
bdo: Base
|
|
14
|
-
big: Base
|
|
15
|
-
blockquote: HTMLQuoteElement
|
|
16
|
-
body: HTMLBodyElement
|
|
17
|
-
br: HTMLBRElement
|
|
18
|
-
button: HTMLButtonElement
|
|
19
|
-
canvas: HTMLCanvasElement
|
|
20
|
-
caption: Base
|
|
21
|
-
cite: HTMLQuoteElement
|
|
22
|
-
code: Base
|
|
23
|
-
col: HTMLTableColElement
|
|
24
|
-
colgroup: HTMLTableColElement
|
|
25
|
-
data: HTMLDataElement
|
|
26
|
-
datalist: HTMLDataListElement
|
|
27
|
-
dd: Base
|
|
28
|
-
del: HTMLModElement
|
|
29
|
-
details: HTMLDetailsElement
|
|
30
|
-
dfn: Base
|
|
31
|
-
dialog: HTMLDialogElement
|
|
32
|
-
div: HTMLDivElement
|
|
33
|
-
dl: HTMLDListElement
|
|
34
|
-
dt: Base
|
|
35
|
-
em: Base
|
|
36
|
-
embed: HTMLEmbedElement
|
|
37
|
-
fieldset: HTMLFieldSetElement
|
|
38
|
-
figcaption: Base
|
|
39
|
-
figure: Base
|
|
40
|
-
footer: Base
|
|
41
|
-
form: HTMLFormElement
|
|
42
|
-
h1: HTMLHeadingElement
|
|
43
|
-
h2: HTMLHeadingElement
|
|
44
|
-
h3: HTMLHeadingElement
|
|
45
|
-
h4: HTMLHeadingElement
|
|
46
|
-
h5: HTMLHeadingElement
|
|
47
|
-
h6: HTMLHeadingElement
|
|
48
|
-
header: Base
|
|
49
|
-
hr: HTMLHRElement
|
|
50
|
-
html: HTMLHtmlElement
|
|
51
|
-
i: Base
|
|
52
|
-
iframe: HTMLIFrameElement
|
|
53
|
-
img: HTMLImageElement
|
|
54
|
-
input: HTMLInputElement
|
|
55
|
-
ins: HTMLModElement
|
|
56
|
-
kbd: Base
|
|
57
|
-
label: HTMLLabelElement
|
|
58
|
-
legend: HTMLLegendElement
|
|
59
|
-
li: HTMLLIElement
|
|
60
|
-
main: Base
|
|
61
|
-
map: HTMLMapElement
|
|
62
|
-
mark: Base
|
|
63
|
-
meter: HTMLMeterElement
|
|
64
|
-
nav: Base
|
|
65
|
-
object: HTMLObjectElement
|
|
66
|
-
ol: HTMLOListElement
|
|
67
|
-
optgroup: HTMLOptGroupElement
|
|
68
|
-
option: HTMLOptionElement
|
|
69
|
-
output: HTMLOutputElement
|
|
70
|
-
p: HTMLParagraphElement
|
|
71
|
-
picture: Base
|
|
72
|
-
pre: HTMLPreElement
|
|
73
|
-
progress: HTMLProgressElement
|
|
74
|
-
q: HTMLQuoteElement
|
|
75
|
-
rp: Base
|
|
76
|
-
rt: Base
|
|
77
|
-
ruby: Base
|
|
78
|
-
s: Base
|
|
79
|
-
samp: Base
|
|
80
|
-
section: Base
|
|
81
|
-
select: HTMLSelectElement
|
|
82
|
-
small: Base
|
|
83
|
-
source: HTMLSourceElement
|
|
84
|
-
span: HTMLSpanElement
|
|
85
|
-
strong: Base
|
|
86
|
-
sub: Base
|
|
87
|
-
summary: Base
|
|
88
|
-
sup: Base
|
|
89
|
-
svg: SVGSVGElement
|
|
90
|
-
table: HTMLTableElement
|
|
91
|
-
tbody: HTMLTableSectionElement
|
|
92
|
-
td: HTMLTableCellElement
|
|
93
|
-
template: HTMLTemplateElement
|
|
94
|
-
textarea: HTMLTextAreaElement
|
|
95
|
-
tfoot: HTMLTableSectionElement
|
|
96
|
-
th: HTMLTableCellElement
|
|
97
|
-
thead: HTMLTableSectionElement
|
|
98
|
-
time: HTMLTimeElement
|
|
99
|
-
tr: HTMLTableRowElement
|
|
100
|
-
track: HTMLTrackElement
|
|
101
|
-
u: Base
|
|
102
|
-
ul: HTMLUListElement
|
|
103
|
-
var: Base
|
|
104
|
-
video: HTMLVideoElement
|
|
105
|
-
wbr: Base
|
|
106
|
-
}
|
package/src/html/htmlTags.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
const HTML_TAGS = [
|
|
2
|
-
'a',
|
|
3
|
-
'abbr',
|
|
4
|
-
'address',
|
|
5
|
-
'area',
|
|
6
|
-
'article',
|
|
7
|
-
'aside',
|
|
8
|
-
'audio',
|
|
9
|
-
'b',
|
|
10
|
-
'bdi',
|
|
11
|
-
'bdo',
|
|
12
|
-
'big',
|
|
13
|
-
'blockquote',
|
|
14
|
-
'body',
|
|
15
|
-
'br',
|
|
16
|
-
'button',
|
|
17
|
-
'canvas',
|
|
18
|
-
'caption',
|
|
19
|
-
'cite',
|
|
20
|
-
'code',
|
|
21
|
-
'col',
|
|
22
|
-
'colgroup',
|
|
23
|
-
'data',
|
|
24
|
-
'datalist',
|
|
25
|
-
'dd',
|
|
26
|
-
'del',
|
|
27
|
-
'details',
|
|
28
|
-
'dfn',
|
|
29
|
-
'dialog',
|
|
30
|
-
'div',
|
|
31
|
-
'dl',
|
|
32
|
-
'dt',
|
|
33
|
-
'em',
|
|
34
|
-
'embed',
|
|
35
|
-
'fieldset',
|
|
36
|
-
'figcaption',
|
|
37
|
-
'figure',
|
|
38
|
-
'footer',
|
|
39
|
-
'form',
|
|
40
|
-
'h1',
|
|
41
|
-
'h2',
|
|
42
|
-
'h3',
|
|
43
|
-
'h4',
|
|
44
|
-
'h5',
|
|
45
|
-
'h6',
|
|
46
|
-
'header',
|
|
47
|
-
'hr',
|
|
48
|
-
'html',
|
|
49
|
-
'i',
|
|
50
|
-
'iframe',
|
|
51
|
-
'img',
|
|
52
|
-
'input',
|
|
53
|
-
'ins',
|
|
54
|
-
'kbd',
|
|
55
|
-
'label',
|
|
56
|
-
'legend',
|
|
57
|
-
'li',
|
|
58
|
-
'main',
|
|
59
|
-
'map',
|
|
60
|
-
'mark',
|
|
61
|
-
'meter',
|
|
62
|
-
'nav',
|
|
63
|
-
'object',
|
|
64
|
-
'ol',
|
|
65
|
-
'optgroup',
|
|
66
|
-
'option',
|
|
67
|
-
'output',
|
|
68
|
-
'p',
|
|
69
|
-
'picture',
|
|
70
|
-
'pre',
|
|
71
|
-
'progress',
|
|
72
|
-
'q',
|
|
73
|
-
'rp',
|
|
74
|
-
'rt',
|
|
75
|
-
'ruby',
|
|
76
|
-
's',
|
|
77
|
-
'samp',
|
|
78
|
-
'section',
|
|
79
|
-
'select',
|
|
80
|
-
'small',
|
|
81
|
-
'source',
|
|
82
|
-
'span',
|
|
83
|
-
'strong',
|
|
84
|
-
'sub',
|
|
85
|
-
'summary',
|
|
86
|
-
'sup',
|
|
87
|
-
'svg',
|
|
88
|
-
'table',
|
|
89
|
-
'tbody',
|
|
90
|
-
'td',
|
|
91
|
-
'template',
|
|
92
|
-
'textarea',
|
|
93
|
-
'tfoot',
|
|
94
|
-
'th',
|
|
95
|
-
'thead',
|
|
96
|
-
'time',
|
|
97
|
-
'tr',
|
|
98
|
-
'track',
|
|
99
|
-
'u',
|
|
100
|
-
'ul',
|
|
101
|
-
'var',
|
|
102
|
-
'video',
|
|
103
|
-
'wbr',
|
|
104
|
-
] as const
|
|
105
|
-
|
|
106
|
-
const HTML_TEXT_TAGS = [
|
|
107
|
-
'abbr',
|
|
108
|
-
'b',
|
|
109
|
-
'bdi',
|
|
110
|
-
'bdo',
|
|
111
|
-
'big',
|
|
112
|
-
'blockquote',
|
|
113
|
-
'cite',
|
|
114
|
-
'code',
|
|
115
|
-
'del',
|
|
116
|
-
'div',
|
|
117
|
-
'dl',
|
|
118
|
-
'dt',
|
|
119
|
-
'em',
|
|
120
|
-
'figcaption',
|
|
121
|
-
'h1',
|
|
122
|
-
'h2',
|
|
123
|
-
'h3',
|
|
124
|
-
'h4',
|
|
125
|
-
'h5',
|
|
126
|
-
'h6',
|
|
127
|
-
'i',
|
|
128
|
-
'ins',
|
|
129
|
-
'kbd',
|
|
130
|
-
'label',
|
|
131
|
-
'legend',
|
|
132
|
-
'li',
|
|
133
|
-
'p',
|
|
134
|
-
'pre',
|
|
135
|
-
'q',
|
|
136
|
-
'rp',
|
|
137
|
-
'rt',
|
|
138
|
-
's',
|
|
139
|
-
'small',
|
|
140
|
-
'span',
|
|
141
|
-
'strong',
|
|
142
|
-
'sub',
|
|
143
|
-
'summary',
|
|
144
|
-
'sup',
|
|
145
|
-
'time',
|
|
146
|
-
'u',
|
|
147
|
-
] as const
|
|
148
|
-
|
|
149
|
-
export type HTMLTags = (typeof HTML_TAGS)[number]
|
|
150
|
-
export type HTMLTextTags = (typeof HTML_TEXT_TAGS)[number]
|
|
151
|
-
export { HTML_TAGS, HTML_TEXT_TAGS }
|
package/src/html/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { HTMLElementAttrs } from './htmlElementAttrs'
|
|
2
|
-
import type { HTMLTags, HTMLTextTags } from './htmlTags'
|
|
3
|
-
import { HTML_TAGS, HTML_TEXT_TAGS } from './htmlTags'
|
|
4
|
-
|
|
5
|
-
type HTMLTagAttrsByTag<T extends HTMLTags> = T extends HTMLTags
|
|
6
|
-
? HTMLElementAttrs[T]
|
|
7
|
-
: Record<string, never>
|
|
8
|
-
|
|
9
|
-
export type { HTMLElementAttrs, HTMLTagAttrsByTag, HTMLTags, HTMLTextTags }
|
|
10
|
-
|
|
11
|
-
export { HTML_TAGS, HTML_TEXT_TAGS }
|
package/src/index.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import compose from './compose'
|
|
2
|
-
import config, { init } from './config'
|
|
3
|
-
import type { CoreContextValue } from './context'
|
|
4
|
-
import Provider, { context } from './context'
|
|
5
|
-
import hoistNonReactStatics from './hoistNonReactStatics'
|
|
6
|
-
import type { HTMLElementAttrs, HTMLTagAttrsByTag, HTMLTags, HTMLTextTags } from './html'
|
|
7
|
-
import { HTML_TAGS, HTML_TEXT_TAGS } from './html'
|
|
8
|
-
import type { IsEmpty } from './isEmpty'
|
|
9
|
-
import isEmpty from './isEmpty'
|
|
10
|
-
import isEqual from './isEqual'
|
|
11
|
-
import type { PyreonUIProps, ThemeMode, ThemeModeInput } from './PyreonUI'
|
|
12
|
-
import { PyreonUI, useMode } from './PyreonUI'
|
|
13
|
-
import type { Render } from './render'
|
|
14
|
-
import render from './render'
|
|
15
|
-
import type { BreakpointKeys, Breakpoints } from './types'
|
|
16
|
-
import useStableValue from './useStableValue'
|
|
17
|
-
import { get, merge, omit, pick, set, throttle } from './utils'
|
|
18
|
-
|
|
19
|
-
export type { CSSEngineConnector } from './config'
|
|
20
|
-
|
|
21
|
-
export type {
|
|
22
|
-
BreakpointKeys,
|
|
23
|
-
Breakpoints,
|
|
24
|
-
CoreContextValue,
|
|
25
|
-
HTMLElementAttrs,
|
|
26
|
-
HTMLTagAttrsByTag,
|
|
27
|
-
HTMLTags,
|
|
28
|
-
HTMLTextTags,
|
|
29
|
-
IsEmpty,
|
|
30
|
-
PyreonUIProps,
|
|
31
|
-
Render,
|
|
32
|
-
ThemeMode,
|
|
33
|
-
ThemeModeInput,
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export {
|
|
37
|
-
compose,
|
|
38
|
-
config,
|
|
39
|
-
context,
|
|
40
|
-
get,
|
|
41
|
-
HTML_TAGS,
|
|
42
|
-
HTML_TEXT_TAGS,
|
|
43
|
-
hoistNonReactStatics,
|
|
44
|
-
init,
|
|
45
|
-
isEmpty,
|
|
46
|
-
isEqual,
|
|
47
|
-
merge,
|
|
48
|
-
omit,
|
|
49
|
-
Provider,
|
|
50
|
-
PyreonUI,
|
|
51
|
-
pick,
|
|
52
|
-
render,
|
|
53
|
-
set,
|
|
54
|
-
throttle,
|
|
55
|
-
useMode,
|
|
56
|
-
useStableValue,
|
|
57
|
-
}
|
package/src/isEmpty.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type IsEmpty = <T extends Record<number | string, any> | any[] | null | undefined>(
|
|
2
|
-
param: T,
|
|
3
|
-
) => T extends null | undefined
|
|
4
|
-
? true
|
|
5
|
-
: keyof T extends never
|
|
6
|
-
? true
|
|
7
|
-
: T extends T[]
|
|
8
|
-
? T[number] extends never
|
|
9
|
-
? true
|
|
10
|
-
: false
|
|
11
|
-
: false
|
|
12
|
-
|
|
13
|
-
const isEmpty = (<T extends Record<number | string, any> | any[] | null | undefined>(param: T) => {
|
|
14
|
-
if (!param) return true
|
|
15
|
-
if (typeof param !== 'object') return true
|
|
16
|
-
if (Array.isArray(param)) return param.length === 0
|
|
17
|
-
return Object.keys(param).length === 0
|
|
18
|
-
}) as IsEmpty
|
|
19
|
-
|
|
20
|
-
export default isEmpty
|
package/src/isEqual.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const isArrayEqual = (a: unknown[], b: unknown[]): boolean => {
|
|
2
|
-
if (a.length !== b.length) return false
|
|
3
|
-
for (let i = 0; i < a.length; i++) {
|
|
4
|
-
if (!isEqual(a[i], b[i])) return false
|
|
5
|
-
}
|
|
6
|
-
return true
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const isObjectEqual = (a: Record<string, unknown>, b: Record<string, unknown>): boolean => {
|
|
10
|
-
const aKeys = Object.keys(a)
|
|
11
|
-
if (aKeys.length !== Object.keys(b).length) return false
|
|
12
|
-
for (const key of aKeys) {
|
|
13
|
-
if (!Object.hasOwn(b, key)) return false
|
|
14
|
-
if (!isEqual(a[key], b[key])) return false
|
|
15
|
-
}
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const isEqual = (a: unknown, b: unknown): boolean => {
|
|
20
|
-
if (Object.is(a, b)) return true
|
|
21
|
-
if (typeof a !== typeof b || a == null || b == null || typeof a !== 'object') return false
|
|
22
|
-
if (Array.isArray(a)) return Array.isArray(b) && isArrayEqual(a, b)
|
|
23
|
-
if (Array.isArray(b)) return false
|
|
24
|
-
return isObjectEqual(a as Record<string, unknown>, b as Record<string, unknown>)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default isEqual
|
package/src/manifest.ts
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { defineManifest } from '@pyreon/manifest'
|
|
2
|
-
|
|
3
|
-
export default defineManifest({
|
|
4
|
-
name: '@pyreon/ui-core',
|
|
5
|
-
title: 'UI Provider + Config',
|
|
6
|
-
tagline:
|
|
7
|
-
'Unified `PyreonUI` provider (theme + mode + config), `useMode()` hook, init() escape hatch',
|
|
8
|
-
description:
|
|
9
|
-
'Foundation layer for the Pyreon UI system. `PyreonUI` is the single provider replacing the previous theme / mode / config split — it accepts a theme, a `mode` of `"light" | "dark" | "system"`, and an optional `inversed` flip, then auto-detects OS preference via `prefers-color-scheme` when `mode="system"`. `useMode()` returns the resolved mode as a reactive signal. The package also exposes the `init()` escape hatch (called internally by `PyreonUI` but available for SSR / test setups), the static `HTML_TAGS` / `HTML_TEXT_TAGS` lists used by the bases, and zero-dep utilities (`get`, `set`, `merge`, `pick`, `omit`, `throttle`, `isEmpty`, `isEqual`).',
|
|
10
|
-
category: 'browser',
|
|
11
|
-
features: [
|
|
12
|
-
'PyreonUI({ theme, mode, inversed }) — single provider replaces 3 separate providers',
|
|
13
|
-
'mode="system" auto-detects OS preference via matchMedia and updates reactively',
|
|
14
|
-
'useMode() returns Signal<"light" | "dark"> resolved against system preference + inversed',
|
|
15
|
-
'init() callable directly for custom environments (tests, SSR without PyreonUI)',
|
|
16
|
-
'enrichTheme() (re-exported from @pyreon/unistyle) merges user theme with defaults',
|
|
17
|
-
'Zero-dep utilities: get, set, merge, pick, omit, throttle, isEmpty, isEqual',
|
|
18
|
-
'HTML_TAGS / HTML_TEXT_TAGS constants drive Element / Text base tag dispatching',
|
|
19
|
-
],
|
|
20
|
-
longExample: `import { PyreonUI, useMode } from '@pyreon/ui-core'
|
|
21
|
-
import { enrichTheme } from '@pyreon/unistyle'
|
|
22
|
-
|
|
23
|
-
// Single provider — wraps theme, mode, and config in one tree
|
|
24
|
-
const theme = enrichTheme({
|
|
25
|
-
colors: { primary: '#3b82f6', secondary: '#6366f1' },
|
|
26
|
-
fonts: { body: 'Inter, sans-serif' },
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
const App = () => (
|
|
30
|
-
<PyreonUI theme={theme} mode="system">
|
|
31
|
-
<MyApp />
|
|
32
|
-
</PyreonUI>
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
// useMode() reads the resolved mode reactively
|
|
36
|
-
function ThemeBadge() {
|
|
37
|
-
const mode = useMode()
|
|
38
|
-
return <div class={mode() === 'dark' ? 'badge-dark' : 'badge-light'}>{mode()}</div>
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// inversed flips the resolved mode (light → dark and vice versa)
|
|
42
|
-
const InvertedSection = () => (
|
|
43
|
-
<PyreonUI inversed>
|
|
44
|
-
<Sidebar />
|
|
45
|
-
</PyreonUI>
|
|
46
|
-
)`,
|
|
47
|
-
api: [
|
|
48
|
-
{
|
|
49
|
-
name: 'PyreonUI',
|
|
50
|
-
kind: 'component',
|
|
51
|
-
signature:
|
|
52
|
-
"(props: { theme?: Theme; mode?: 'light' | 'dark' | 'system'; inversed?: boolean; children: VNodeChild }) => VNodeChild",
|
|
53
|
-
summary:
|
|
54
|
-
"Unified provider replacing the previous theme / mode / config split (3 nested providers became 1). Accepts an enriched `theme` object (merge with defaults via `enrichTheme()`), a `mode` of `'light' | 'dark' | 'system'`, and an optional `inversed` flip. When `mode='system'`, the provider subscribes to `matchMedia('(prefers-color-scheme: dark)')` and re-resolves the mode reactively. Calls `init()` internally so consumers don\\\'t need to wire it up themselves. Whole-theme swaps (user-preference themes) propagate through the styler resolver and re-resolve CSS without remounting the VNode.",
|
|
55
|
-
example: `import { PyreonUI } from "@pyreon/ui-core"
|
|
56
|
-
import { enrichTheme } from "@pyreon/unistyle"
|
|
57
|
-
|
|
58
|
-
const theme = enrichTheme({ colors: { primary: "#3b82f6" } })
|
|
59
|
-
|
|
60
|
-
<PyreonUI theme={theme} mode="system">
|
|
61
|
-
<App />
|
|
62
|
-
</PyreonUI>
|
|
63
|
-
|
|
64
|
-
// mode="system" auto-detects OS dark mode via prefers-color-scheme
|
|
65
|
-
// inversed flips the resolved mode (light↔dark)`,
|
|
66
|
-
mistakes: [
|
|
67
|
-
'Using `ThemeProvider` + `ModeProvider` + `ConfigProvider` separately — `PyreonUI` is the single replacement covering all three',
|
|
68
|
-
'Forgetting `enrichTheme()` — raw theme objects miss default breakpoints / spacing / unit utilities',
|
|
69
|
-
'Destructuring `props` inside the provider — components run once; destructuring captures values at setup. Read `props.mode` lazily inside reactive scopes',
|
|
70
|
-
'Re-augmenting the `ThemeDefault` / `StylesDefault` interfaces in your app — `@pyreon/ui-theme` already augments them; double-augmentation throws TS2320',
|
|
71
|
-
],
|
|
72
|
-
seeAlso: ['useMode', 'enrichTheme', 'init'],
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
name: 'useMode',
|
|
76
|
-
kind: 'hook',
|
|
77
|
-
signature: "useMode(): Signal<'light' | 'dark'>",
|
|
78
|
-
summary:
|
|
79
|
-
"Returns the currently resolved mode as a reactive signal — `'light'` or `'dark'`. When the nearest `PyreonUI` ancestor uses `mode='system'`, the signal reflects the OS preference and updates when the user changes their system setting. When `inversed` is true on any ancestor, the mode is flipped before resolution. Component-scoped subscription — readers re-run only when the resolved mode actually changes.",
|
|
80
|
-
example: `import { useMode } from "@pyreon/ui-core"
|
|
81
|
-
|
|
82
|
-
const mode = useMode()
|
|
83
|
-
// mode() returns "light" or "dark" (resolved, reactive)
|
|
84
|
-
// Reflects OS preference when PyreonUI mode="system"`,
|
|
85
|
-
mistakes: [
|
|
86
|
-
'Reading `useMode()` without calling it — the value is a `Signal`; use `mode()` to read',
|
|
87
|
-
'Using `useMode()` outside any `PyreonUI` ancestor — falls back to a default but loses the reactive system / inversed handling',
|
|
88
|
-
],
|
|
89
|
-
seeAlso: ['PyreonUI'],
|
|
90
|
-
},
|
|
91
|
-
],
|
|
92
|
-
gotchas: [
|
|
93
|
-
{
|
|
94
|
-
label: 'Provider replacement',
|
|
95
|
-
note:
|
|
96
|
-
'The legacy split (separate theme / mode / config providers) is removed. `PyreonUI` is the only correct mount; calling `init()` directly is the escape hatch for SSR or test environments where the provider tree is unavailable.',
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
label: 'System-mode subscription',
|
|
100
|
-
note:
|
|
101
|
-
'`mode="system"` lazily creates a `matchMedia(\'(prefers-color-scheme: dark)\')` subscription on first read; the listener stays alive for the document lifetime, so a single subscription handles every `useMode()` consumer.',
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
})
|