amateras 0.0.1 → 0.1.1

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/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Amateras
2
2
  Amateras is a DOM Utility library.
3
3
 
4
- ## Build DOM tree in JS
4
+ ## Build DOM Tree in JS
5
5
  ```ts
6
6
  import 'amateras';
7
7
 
8
8
  $(document.body).content([
9
- $('h1').attr({ class: 'title' }).content('Hello, World')
9
+ $('h1').class('title').content('Hello, World')
10
10
  ])
11
11
  ```
12
12
 
@@ -80,4 +80,11 @@ function NameCard(name: string, avatarURL: string) {
80
80
  $(document.body).content([
81
81
  $(NameCard, 'The dancing man', 'https://media.tenor.com/x8v1oNUOmg4AAAAM/rickroll-roll.gif')
82
82
  ])
83
- ```
83
+ ```
84
+
85
+ ## Packages
86
+ |-|-|
87
+ |Package name|Size|Size(gzip)|Description|
88
+ |amateras|5.56 kB|2.35 kB|Core
89
+ |amateras/html|0.66 kB|0.28 kB|Import HTMLElement types and methods|
90
+ |[amateras/css](./ext/css/README.md)|3.74 kB|1.40 kB|Style in JS|
@@ -0,0 +1,109 @@
1
+ # amateras/css
2
+
3
+ ## Usage
4
+ ```ts
5
+ import 'amateras';
6
+ import 'amateras/css';
7
+ ```
8
+
9
+ ## Define Style
10
+ ```ts
11
+ const style = $.css({
12
+ backgroundColor: 'black',
13
+ margin: 0,
14
+
15
+ 'p': {
16
+ color: 'blue'
17
+
18
+ '@media (max-width: 800px)': {
19
+ color: 'red'
20
+ }
21
+ }
22
+ })
23
+
24
+ $(document.body).css(style).content([
25
+ $('p').content('Text with blue color.')
26
+ ]);
27
+ ```
28
+
29
+ ## Define Style in Method Chain
30
+ ```ts
31
+ $(document.body).content([
32
+ $('h1').css({ color: 'red' }).content('This is a title with red color!')
33
+ ])
34
+ ```
35
+
36
+ ## Define Variables
37
+
38
+ ### Single Variable
39
+ ```ts
40
+ const largeText = $.css.variables('1.2rem');
41
+
42
+ $.css({
43
+ fontSize: largeText
44
+ })
45
+ ```
46
+
47
+ ### Variable Group
48
+ ```ts
49
+ const text = $.css.variables({
50
+ small: '0.8rem',
51
+ medium: '1rem',
52
+ large: '1.2rem'
53
+ })
54
+
55
+ $.css({
56
+ fontSize: text.large
57
+ })
58
+ ```
59
+
60
+ ## Define Keyframes
61
+ ```ts
62
+ const keyframes = $.css.keyframes({
63
+ fadeIn: {
64
+ '0%': { opacity: 0 },
65
+ '100%': { opacity: 1 }
66
+ },
67
+ fadeOut: {
68
+ from: { opacity: 1 },
69
+ to: { opacity: 0 }
70
+ }
71
+ })
72
+
73
+ $.css({
74
+ animation: keyframes.fadeIn
75
+ })
76
+ ```
77
+
78
+ ## Define CSS Rules with Selectors
79
+ ```ts
80
+ $.CSS({
81
+ 'html': {
82
+ fontSize: '18px',
83
+ fontFamily: 'Noto Sans',
84
+
85
+ 'body': {
86
+ margin: 0,
87
+
88
+ '.title': {
89
+ color: 'red'
90
+ }
91
+ }
92
+ },
93
+
94
+ '@media (max-width: 800px)': {
95
+ 'html': {
96
+ fontSize: '1rem',
97
+
98
+ '@media (orientation: landscape)': {
99
+ fontSize: '1.2rem'
100
+ },
101
+ }
102
+ },
103
+ })
104
+
105
+ $(document.body).content([
106
+ $('h1').class('title').content('A red color title.')
107
+ ])
108
+
109
+ ```
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@amateras/css",
3
+ "peerDependencies": {
4
+ "amateras": "../../"
5
+ },
6
+ "imports": {
7
+ "#structure/*": "./src/structure/*.ts"
8
+ }
9
+ }
@@ -0,0 +1,442 @@
1
+ import { _instanceof, _Object_assign, _Object_entries, _Object_fromEntries, isObject, isUndefined } from "amateras/lib/native";
2
+ import { randomId } from "amateras/lib/randomId";
3
+ import { $Element } from "amateras/node/$Element";
4
+ import { $CSSDeclaration } from "#structure/$CSSDeclaration";
5
+ import { $CSSMediaRule } from "#structure/$CSSMediaRule";
6
+ import { $CSSRule } from "#structure/$CSSRule";
7
+ import { $CSSStyleRule } from "#structure/$CSSStyleRule";
8
+ import { $CSSKeyframesRule } from "#structure/$CSSKeyframesRule";
9
+ import { $CSSVariable } from "#structure/$CSSVariable";
10
+ import { $CSSKeyframeRule } from "#structure/$CSSKeyframeRule";
11
+
12
+ declare module 'amateras/core' {
13
+ export namespace $ {
14
+ export function css(options: $CSSOptions): $CSSStyleRule
15
+ export function CSS(options: $CSSSelectorType | $CSSMediaSelectorType<false> | $CSSKeyframesSelectorType): void
16
+
17
+ export namespace css {
18
+ export function variables(value: string): $CSSVariable;
19
+ export function variables<T extends $CSSVariableType>(options: T, conditions?: $CSSVariableConditionType<T>): { [key in keyof T]: $CSSVariable }
20
+ export function keyframes<T extends { [key: string]: $CSSKeyframesType }>(options: T): { [key in keyof T]: $CSSKeyframesRule };
21
+ export const stylesheet: CSSStyleSheet;
22
+ }
23
+ }
24
+ }
25
+
26
+ declare module 'amateras/node/$Element' {
27
+ export interface $Element {
28
+ css(...options: $CSSOptions[]): this;
29
+ }
30
+ }
31
+
32
+ const generatedIds = new Set<string>();
33
+ function generateId(lettercase?: 'any' | 'lower' | 'upper'): string {
34
+ const id = randomId({lettercase: lettercase});
35
+ if (generatedIds.has(id)) return generateId(lettercase);
36
+ generatedIds.add(id);
37
+ return id;
38
+ }
39
+
40
+ const stylesheet = new CSSStyleSheet();
41
+ document.adoptedStyleSheets.push(stylesheet);
42
+
43
+ function processCSSOptions<T extends $CSSStyleRule | $CSSKeyframeRule>(
44
+ rule: T,
45
+ options: $CSSDeclarationType | $CSSSelectorType | $CSSMediaSelectorType<boolean>,
46
+ context: string[] = [],
47
+ ): T {
48
+ for (const [key, value] of _Object_entries(options)) {
49
+ if (isUndefined(value)) continue;
50
+ if (isObject(value) && !_instanceof(value, $CSSKeyframesRule) && !_instanceof(value, $CSSVariable))
51
+ rule.addRule( createRule(key, value, context) );
52
+ else {
53
+ const declaration = new $CSSDeclaration(key, `${value}`);
54
+ rule.declarations.set(declaration.key, declaration);
55
+ }
56
+ }
57
+ return rule;
58
+ }
59
+
60
+ function createRule(selector: string, options: $CSSOptions, context: string[] = [], global = false) {
61
+ if (selector.startsWith('@media')) return createMediaRule(selector.replace('@media ', ''), options, context, global);
62
+ if (selector.startsWith('@keyframes')) return createKeyframesRule(selector.replace('@keyframes ', ''), options as $CSSKeyframesType)
63
+ return createStyleRule(options, [...context, selector]);
64
+ }
65
+
66
+ function createStyleRule<T extends $CSSRule>(options: T, context?: string[]): T;
67
+ function createStyleRule<T extends $CSSOptions>(options: T, context?: string[]): $CSSStyleRule;
68
+ function createStyleRule<T extends $CSSOptions>(options: T, context: string[] = []) {
69
+ if (_instanceof(options, $CSSRule)) return options;
70
+ return processCSSOptions(new $CSSStyleRule(context), options, context);
71
+ }
72
+
73
+ function createMediaRule(condition: string, options: $CSSOptions, context: string[] = [], global: boolean) {
74
+ const rule = new $CSSMediaRule(condition);
75
+ // create media rule from $.CSS
76
+ if (global) _Object_entries(options).forEach(([key, value]) => rule.addRule( createRule(key, value, context) ))
77
+ // create from $.css
78
+ else rule.addRule( createStyleRule(options, context) );
79
+ return rule;
80
+ }
81
+
82
+ function createKeyframesRule(name: string, options: $CSSKeyframesType) {
83
+ const rule = new $CSSKeyframesRule(name);
84
+ _Object_entries(options).forEach(([key, value]) => {
85
+ rule.addRule( processCSSOptions(new $CSSKeyframeRule(key), value) );
86
+ })
87
+ return rule;
88
+ }
89
+
90
+ function insertRule(rule: $CSSRule, recursive = false) {
91
+ if (_instanceof(rule, $CSSStyleRule) && !CSS.supports(`selector(${rule.selector})`)) return rule;
92
+ stylesheet.insertRule(rule.css, stylesheet.cssRules.length);
93
+ if (_instanceof(rule, $CSSKeyframesRule)) return rule;
94
+ if (!_instanceof(rule, $CSSMediaRule)) rule.rules.forEach(rule => insertRule(rule));
95
+ else if (!recursive) rule.mediaRules.forEach(rule => insertRule(rule, true));
96
+ return rule;
97
+ }
98
+
99
+ _Object_assign($, {
100
+ css(options: $CSSOptions) {
101
+ if (_instanceof(options, $CSSRule)) return options;
102
+ const className = `.${generateId()}`;
103
+ const rule = createStyleRule(options, [className]);
104
+ rule.className = className;
105
+ return insertRule( rule );
106
+ },
107
+ CSS(options: $CSSSelectorType | $CSSMediaRule) {
108
+ return _Object_entries(options).map(([selector, declarations]) => {
109
+ return insertRule( createRule(selector, declarations, [], true) );
110
+ })
111
+ }
112
+ })
113
+
114
+ _Object_assign($.css, {
115
+ stylesheet: stylesheet,
116
+ variables<T extends $CSSVariableType | string>(options: T, conditions?: $CSSVariableConditionType<T>) {
117
+ if (isObject(options)) {
118
+ const variables = _Object_fromEntries(_Object_entries(options).map(([key, value]) => [
119
+ key,
120
+ new $CSSVariable(`${key.replaceAll(/([A-Z])/g, ((_, $1) => `-${$1.toLowerCase()}`))}_${generateId('lower')}`, `${value}`)
121
+ ]))
122
+
123
+ const conditionObj = conditions ? _Object_entries(conditions).map(([condition, _options]) => [
124
+ condition,
125
+ _Object_fromEntries(_Object_entries(_options).map(([key, value]) => [`--${variables[key]?.key}`, `${value}`] as const))
126
+ ] as const) : [];
127
+
128
+ $.CSS({':root': {
129
+ ..._Object_fromEntries(_Object_entries(variables).map(([_, varobj]) => [`--${varobj.key}`, varobj.value])),
130
+ ..._Object_fromEntries(conditionObj)
131
+ }})
132
+
133
+ return variables;
134
+ } else {
135
+ const variable = new $CSSVariable(generateId('lower'), options);
136
+ $.CSS({':root': {[`--${variable.key}`]: variable.value}});
137
+ return variable;
138
+ }
139
+ },
140
+ keyframes(options: $CSSKeyframesType) {
141
+ return _Object_fromEntries( _Object_entries(options).map(([name, value]) => {
142
+ return [name, insertRule( createKeyframesRule(`${name}_${generateId()}`, value) )];
143
+ }) )
144
+ }
145
+ })
146
+
147
+ _Object_assign($Element.prototype, {
148
+ css(this: $Element, ...options: $CSSOptions[]) {
149
+ options.forEach(options => {
150
+ const rule = $.css(options);
151
+ this.addClass(rule.context[0]?.slice(1) as string);
152
+ })
153
+ return this;
154
+ }
155
+ })
156
+
157
+ export * from "#structure/$CSSDeclaration";
158
+ export * from "#structure/$CSSKeyframeRule";
159
+ export * from "#structure/$CSSKeyframesRule";
160
+ export * from "#structure/$CSSMediaRule";
161
+ export * from "#structure/$CSSRule";
162
+ export * from "#structure/$CSSStyleRule";
163
+ export * from "#structure/$CSSVariable";
164
+
165
+ type $CSSOptions = $CSSDeclarationType | $CSSSelectorType | $CSSStyleRule | $CSSMediaSelectorType<true>;
166
+ type $CSSValueType = '' | 'unset' | 'initial' | 'inherit' | string & {} | number | $CSSVariable
167
+ type $CSSDeclarationType = { [key in keyof $CSSDeclarationMap]?: $CSSDeclarationMap[key] }
168
+ type $CSSSelectorType = { [key: string & {}]: $CSSOptions }
169
+ type $CSSMediaSelectorType<Nested extends boolean> = { [key: `@media ${string}`]: Nested extends true ? $CSSOptions : $CSSSelectorType | $CSSMediaSelectorType<Nested> }
170
+ type $CSSVariableType<T = any> = { [key in keyof T]: $CSSValueType }
171
+ type $CSSVariableConditionType<T extends $CSSVariableType | string> = T extends string ? { [key: string]: $CSSValueType } : { [key: string]: $CSSVariableType<T> }
172
+ type $CSSKeyframesSelectorType = { [key: `@keyframes ${string}`]: $CSSKeyframesType }
173
+ type $CSSKeyframesType = { [key: `${number}%`]: $CSSDeclarationType } | { from?: $CSSDeclarationType, to?: $CSSDeclarationType }
174
+
175
+ type $CSSDeclarationMap = {
176
+ [key in keyof CSSStyleDeclaration]: $CSSValueType;
177
+ } | {
178
+ alignContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'stretch' | 'normal';
179
+ alignItems?: 'normal' | 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline';
180
+ alignSelf?: 'auto' | 'normal' | 'stretch' | 'center' | 'flex-start' | 'flex-end' | 'baseline';
181
+ all?: 'initial' | 'inherit' | 'unset';
182
+ animation?: string | $CSSKeyframesRule;
183
+ animationDelay?: string;
184
+ animationDirection?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';
185
+ animationDuration?: string;
186
+ animationFillMode?: 'none' | 'forwards' | 'backwards' | 'both';
187
+ animationIterationCount?: 'infinite' | number;
188
+ animationName?: string | $CSSKeyframesRule;
189
+ animationPlayState?: 'running' | 'paused';
190
+ animationTimingFunction?: 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' | 'step-start' | 'step-end';
191
+ animationComposition?: 'replace' | 'add' | 'accumulate';
192
+ backdropFilter?: string;
193
+ backfaceVisibility?: 'visible' | 'hidden';
194
+ background?: string;
195
+ backgroundAttachment?: 'scroll' | 'fixed' | 'local';
196
+ backgroundBlendMode?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity';
197
+ backgroundClip?: 'border-box' | 'padding-box' | 'content-box' | 'text';
198
+ backgroundColor?: string;
199
+ backgroundImage?: string;
200
+ backgroundOrigin?: 'border-box' | 'padding-box' | 'content-box';
201
+ backgroundPosition?: string;
202
+ backgroundRepeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' | 'space' | 'round';
203
+ backgroundSize?: 'auto' | 'cover' | 'contain';
204
+ border?: string;
205
+ borderBottom?: string;
206
+ borderBottomColor?: string;
207
+ borderBottomLeftRadius?: string;
208
+ borderBottomRightRadius?: string;
209
+ borderBottomStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
210
+ borderBottomWidth?: string;
211
+ borderCollapse?: 'collapse' | 'separate';
212
+ borderColor?: string;
213
+ borderImage?: string;
214
+ borderImageOutset?: string;
215
+ borderImageRepeat?: 'stretch' | 'repeat' | 'round' | 'space';
216
+ borderImageSlice?: string;
217
+ borderImageSource?: string;
218
+ borderImageWidth?: string;
219
+ borderLeft?: string;
220
+ borderLeftColor?: string;
221
+ borderLeftStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
222
+ borderLeftWidth?: string;
223
+ borderRadius?: string;
224
+ borderRight?: string;
225
+ borderRightColor?: string;
226
+ borderRightStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
227
+ borderRightWidth?: string;
228
+ borderSpacing?: string;
229
+ borderStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
230
+ borderTop?: string;
231
+ borderTopColor?: string;
232
+ borderTopLeftRadius?: string;
233
+ borderTopRightRadius?: string;
234
+ borderTopStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
235
+ borderTopWidth?: string;
236
+ borderWidth?: string;
237
+ bottom?: string;
238
+ boxShadow?: string;
239
+ boxSizing?: 'content-box' | 'border-box';
240
+ breakAfter?: 'auto' | 'avoid' | 'always' | 'all' | 'avoid-page' | 'page' | 'left' | 'right' | 'recto' | 'verso' | 'column' | 'avoid-column';
241
+ breakBefore?: 'auto' | 'avoid' | 'always' | 'all' | 'avoid-page' | 'page' | 'left' | 'right' | 'recto' | 'verso' | 'column' | 'avoid-column';
242
+ breakInside?: 'auto' | 'avoid' | 'avoid-page' | 'avoid-column';
243
+ captionSide?: 'top' | 'bottom';
244
+ caretColor?: string;
245
+ clear?: 'none' | 'left' | 'right' | 'both';
246
+ clip?: string;
247
+ clipPath?: string;
248
+ color?: string;
249
+ columnCount?: 'auto' | number;
250
+ columnFill?: 'balance' | 'auto';
251
+ columnGap?: string;
252
+ columnRule?: string;
253
+ columnRuleColor?: string;
254
+ columnRuleStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
255
+ columnRuleWidth?: string;
256
+ columnSpan?: 'none' | 'all';
257
+ columnWidth?: string;
258
+ columns?: string;
259
+ content?: string;
260
+ counterIncrement?: string;
261
+ counterReset?: string;
262
+ cursor?: 'auto' | 'default' | 'none' | 'context-menu' | 'help' | 'pointer' | 'progress' | 'wait' | 'cell' | 'crosshair' | 'text' | 'vertical-text' | 'alias' | 'copy' | 'move' | 'no-drop' | 'not-allowed' | 'e-resize' | 'n-resize' | 'ne-resize' | 'nw-resize' | 's-resize' | 'se-resize' | 'sw-resize' | 'w-resize' | 'ew-resize' | 'ns-resize' | 'nesw-resize' | 'nwse-resize' | 'col-resize' | 'row-resize' | 'all-scroll' | 'zoom-in' | 'zoom-out' | 'grab' | 'grabbing';
263
+ direction?: 'ltr' | 'rtl';
264
+ display?: 'block' | 'inline' | 'inline-block' | 'flex' | 'inline-flex' | 'grid' | 'inline-grid' | 'flow-root' | 'none' | 'contents' | 'table' | 'table-row' | 'table-cell' | 'table-column' | 'table-column-group' | 'table-header-group' | 'table-footer-group' | 'table-row-group' | 'list-item';
265
+ emptyCells?: 'show' | 'hide';
266
+ filter?: string;
267
+ flex?: string;
268
+ flexBasis?: string;
269
+ flexDirection?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
270
+ flexFlow?: string;
271
+ flexGrow?: number;
272
+ flexShrink?: number;
273
+ flexWrap?: 'nowrap' | 'wrap' | 'wrap-reverse';
274
+ float?: 'left' | 'right' | 'none';
275
+ font?: string;
276
+ fontFamily?: string;
277
+ fontFeatureSettings?: string;
278
+ fontKerning?: 'auto' | 'normal' | 'none';
279
+ fontLanguageOverride?: string;
280
+ fontOpticalSizing?: 'auto' | 'none';
281
+ fontSize?: string;
282
+ fontSizeAdjust?: string;
283
+ fontStretch?: 'normal' | 'ultra-condensed' | 'extra-condensed' | 'condensed' | 'semi-condensed' | 'semi-expanded' | 'expanded' | 'extra-expanded' | 'ultra-expanded';
284
+ fontStyle?: 'normal' | 'italic' | 'oblique';
285
+ fontSynthesis?: string;
286
+ fontVariant?: 'normal' | 'small-caps';
287
+ fontVariantCaps?: 'normal' | 'small-caps' | 'all-small-caps' | 'petite-caps' | 'all-petite-caps' | 'unicase' | 'titling-caps';
288
+ fontVariantEastAsian?: string;
289
+ fontVariantLigatures?: string;
290
+ fontVariantNumeric?: string;
291
+ fontVariantPosition?: 'normal' | 'sub' | 'super';
292
+ fontWeight?: 'normal' | 'bold' | 'bolder' | 'lighter' | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
293
+ gap?: string;
294
+ grid?: string;
295
+ gridArea?: string;
296
+ gridAutoColumns?: string;
297
+ gridAutoFlow?: 'row' | 'column' | 'dense' | 'row dense' | 'column dense';
298
+ gridAutoRows?: string;
299
+ gridColumn?: string;
300
+ gridColumnEnd?: string;
301
+ gridColumnGap?: string;
302
+ gridColumnStart?: string;
303
+ gridGap?: string;
304
+ gridRow?: string;
305
+ gridRowEnd?: string;
306
+ gridRowGap?: string;
307
+ gridRowStart?: string;
308
+ gridTemplate?: string;
309
+ gridTemplateAreas?: string;
310
+ gridTemplateColumns?: string;
311
+ gridTemplateRows?: string;
312
+ height?: string;
313
+ hyphens?: 'none' | 'manual' | 'auto';
314
+ imageRendering?: 'auto' | 'crisp-edges' | 'pixelated';
315
+ isolation?: 'auto' | 'isolate';
316
+ justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';
317
+ justifyItems?: 'normal' | 'stretch' | 'center' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'left' | 'right';
318
+ justifySelf?: 'auto' | 'normal' | 'stretch' | 'center' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'left' | 'right';
319
+ left?: string;
320
+ letterSpacing?: 'normal';
321
+ lineHeight?: 'normal' | number;
322
+ listStyle?: string;
323
+ listStyleImage?: string;
324
+ listStylePosition?: 'inside' | 'outside';
325
+ listStyleType?: 'disc' | 'circle' | 'square' | 'decimal' | 'georgian' | 'trad-chinese-informal' | 'none';
326
+ margin?: string;
327
+ marginBottom?: string;
328
+ marginLeft?: string;
329
+ marginRight?: string;
330
+ marginTop?: string;
331
+ mask?: string;
332
+ maskClip?: string;
333
+ maskComposite?: string;
334
+ maskImage?: string;
335
+ maskMode?: string;
336
+ maskOrigin?: string;
337
+ maskPosition?: string;
338
+ maskRepeat?: string;
339
+ maskSize?: string;
340
+ maskType?: string;
341
+ maxHeight?: string;
342
+ maxWidth?: string;
343
+ minHeight?: string;
344
+ minWidth?: string;
345
+ mixBlendMode?: 'normal' | 'multiply' | 'screen' | 'overlay' | 'darken' | 'lighten' | 'color-dodge' | 'color-burn' | 'hard-light' | 'soft-light' | 'difference' | 'exclusion' | 'hue' | 'saturation' | 'color' | 'luminosity';
346
+ objectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down';
347
+ objectPosition?: string;
348
+ opacity?: number;
349
+ order?: number;
350
+ outline?: string;
351
+ outlineColor?: string;
352
+ outlineOffset?: string;
353
+ outlineStyle?: 'none' | 'hidden' | 'dotted' | 'dashed' | 'solid' | 'double' | 'groove' | 'ridge' | 'inset' | 'outset';
354
+ outlineWidth?: string;
355
+ overflow?: 'visible' | 'hidden' | 'scroll' | 'auto';
356
+ overflowWrap?: 'normal' | 'break-word' | 'anywhere';
357
+ overflowX?: 'visible' | 'hidden' | 'scroll' | 'auto';
358
+ overflowY?: 'visible' | 'hidden' | 'scroll' | 'auto';
359
+ overscrollBehavior?: 'auto' | 'contain' | 'none';
360
+ overscrollBehaviorX?: 'auto' | 'contain' | 'none';
361
+ overscrollBehaviorY?: 'auto' | 'contain' | 'none';
362
+ padding?: string;
363
+ paddingBottom?: string;
364
+ paddingLeft?: string;
365
+ paddingRight?: string;
366
+ paddingTop?: string;
367
+ pageBreakAfter?: 'auto' | 'always' | 'avoid' | 'left' | 'right';
368
+ pageBreakBefore?: 'auto' | 'always' | 'avoid' | 'left' | 'right';
369
+ pageBreakInside?: 'auto' | 'avoid';
370
+ paintOrder?: string;
371
+ perspective?: string;
372
+ perspectiveOrigin?: string;
373
+ placeContent?: string;
374
+ placeItems?: string;
375
+ placeSelf?: string;
376
+ pointerEvents?: 'auto' | 'none';
377
+ position?: 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky';
378
+ quotes?: string;
379
+ resize?: 'none' | 'both' | 'horizontal' | 'vertical' | 'block' | 'inline';
380
+ right?: string;
381
+ rotate?: string;
382
+ rowGap?: string;
383
+ scale?: string;
384
+ scrollBehavior?: 'auto' | 'smooth';
385
+ shapeRendering?: 'auto' | 'optimizeSpeed' | 'crispEdges' | 'geometricPrecision';
386
+ stopColor?: string;
387
+ stopOpacity?: string;
388
+ stroke?: string;
389
+ strokeDasharray?: string;
390
+ strokeDashoffset?: string;
391
+ strokeLinecap?: 'butt' | 'round' | 'square';
392
+ strokeLinejoin?: 'miter' | 'round' | 'bevel';
393
+ strokeMiterlimit?: string;
394
+ strokeOpacity?: string;
395
+ strokeWidth?: string;
396
+ tabSize?: string;
397
+ tableLayout?: 'auto' | 'fixed';
398
+ textAlign?: 'left' | 'right' | 'center' | 'justify' | 'start' | 'end';
399
+ textAlignLast?: 'auto' | 'left' | 'right' | 'center' | 'justify' | 'start' | 'end';
400
+ textAnchor?: 'start' | 'middle' | 'end';
401
+ textCombineUpright?: 'none' | 'all';
402
+ textDecoration?: string;
403
+ textDecorationColor?: string;
404
+ textDecorationLine?: 'none' | 'underline' | 'overline' | 'line-through' | 'grammar-error' | 'spelling-error';
405
+ textDecorationStyle?: 'solid' | 'double' | 'dotted' | 'dashed' | 'wavy';
406
+ textDecorationThickness?: string;
407
+ textDecorationSkipInk?: 'auto' | 'none';
408
+ textEmphasis?: string;
409
+ textIndent?: string;
410
+ textJustify?: 'auto' | 'inter-word' | 'inter-character' | 'none';
411
+ textOrientation?: 'mixed' | 'upright' | 'sideways';
412
+ textOverflow?: 'clip' | 'ellipsis';
413
+ textRendering?: 'auto' | 'optimizeSpeed' | 'optimizeLegibility' | 'geometricPrecision';
414
+ textShadow?: string;
415
+ textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase';
416
+ textUnderlineOffset?: string;
417
+ textUnderlinePosition?: 'auto' | 'under' | 'left' | 'right';
418
+ top?: string;
419
+ touchAction?: 'auto' | 'none' | 'pan-x' | 'pan-y' | 'manipulation';
420
+ transform?: string;
421
+ transformBox?: 'border-box' | 'fill-box' | 'view-box';
422
+ transformOrigin?: string;
423
+ transformStyle?: 'flat' | 'preserve-3d';
424
+ transition?: string;
425
+ transitionDelay?: string;
426
+ transitionDuration?: string;
427
+ transitionProperty?: string;
428
+ transitionTimingFunction?: 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' | 'step-start' | 'step-end';
429
+ translate?: string;
430
+ unicodeBidi?: 'normal' | 'embed' | 'isolate' | 'bidi-override' | 'isolate-override' | 'plaintext';
431
+ userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all';
432
+ verticalAlign?: 'baseline' | 'sub' | 'super' | 'text-top' | 'text-bottom' | 'middle' | 'top' | 'bottom';
433
+ visibility?: 'visible' | 'hidden' | 'collapse';
434
+ whiteSpace?: 'normal' | 'nowrap' | 'pre' | 'pre-wrap' | 'pre-line' | 'break-spaces';
435
+ width?: string;
436
+ willChange?: string;
437
+ wordBreak?: 'normal' | 'break-all' | 'keep-all' | 'break-word';
438
+ wordSpacing?: string;
439
+ wordWrap?: 'normal' | 'break-word';
440
+ writingMode?: 'horizontal-tb' | 'vertical-rl' | 'vertical-lr';
441
+ zIndex?: 'auto' | number;
442
+ };
@@ -9,4 +9,8 @@ export class $CSSDeclaration {
9
9
  get property() {
10
10
  return this.key.replaceAll(/([A-Z])/g, (_, s1) => `-${s1}`).toLowerCase();
11
11
  }
12
+
13
+ toString() {
14
+ return `${this.property}: ${this.value};`
15
+ }
12
16
  }
@@ -0,0 +1,13 @@
1
+ import { $CSSStyleRule } from "#structure/$CSSStyleRule";
2
+
3
+ export class $CSSKeyframeRule extends $CSSStyleRule {
4
+ keyframe: string
5
+ constructor(keyframe: string) {
6
+ super();
7
+ this.keyframe = keyframe;
8
+ }
9
+
10
+ get css(): string {
11
+ return `${this.keyframe} { ${Array.from(this.declarations).map(([_, dec]) => `${dec}`).join(' ')} }`
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ import { $CSSRule } from "#structure/$CSSRule";
2
+
3
+ export class $CSSKeyframesRule extends $CSSRule {
4
+ name: string;
5
+ constructor(name: string) {
6
+ super();
7
+ this.name = name;
8
+ }
9
+
10
+ toString(): string {
11
+ return this.name;
12
+ }
13
+
14
+ get css() {
15
+ return `@keyframes ${this.name} { ${Array.from(this.rules).map(rule => rule.css).join(' ')} }`
16
+ }
17
+ }
@@ -0,0 +1,30 @@
1
+ import { _Array_from, _instanceof } from "amateras/lib/native";
2
+ import { $CSSRule } from "#structure/$CSSRule";
3
+ import { $CSSStyleRule } from "./$CSSStyleRule";
4
+
5
+ export class $CSSMediaRule extends $CSSRule {
6
+ condition: string;
7
+ constructor(condition: string) {
8
+ super();
9
+ this.condition = condition;
10
+ }
11
+
12
+ get css(): string {
13
+ function findOwnerMediaRule(rule: $CSSRule, contextRules: $CSSMediaRule[]) {
14
+ const ownerRule = rule.ownerRule;
15
+ if (!ownerRule) return contextRules;
16
+ if (_instanceof(ownerRule, $CSSMediaRule)) return findOwnerMediaRule(ownerRule, [ownerRule, ...contextRules]);
17
+ else return findOwnerMediaRule(ownerRule, contextRules);
18
+ }
19
+
20
+ function findChildRules(rule: $CSSRule, rules: $CSSStyleRule[] = []) {
21
+ _Array_from(rule.rules).forEach((_rule => {
22
+ if (!_instanceof(_rule, $CSSStyleRule)) return;
23
+ rules.push(_rule);
24
+ return findChildRules(_rule, rules);
25
+ }))
26
+ return rules
27
+ }
28
+ return `@media ${findOwnerMediaRule(this, [this]).map(rule => rule.condition).join(' and ')} { ${findChildRules(this).map(rule => rule.css).join(' ')} }`
29
+ }
30
+ }
@@ -0,0 +1,25 @@
1
+ import { _instanceof } from "amateras/lib/native";
2
+ import { $CSSMediaRule } from "#structure/$CSSMediaRule";
3
+
4
+ export abstract class $CSSRule {
5
+ rules = new Set<$CSSRule>();
6
+ ownerRule: $CSSRule | null = null;
7
+ constructor() {}
8
+
9
+ abstract get css(): string;
10
+
11
+ get mediaRules() {
12
+ const rules: $CSSMediaRule[] = []
13
+ this.rules.forEach(rule => {
14
+ if (_instanceof(rule, $CSSMediaRule)) rules.push(rule);
15
+ rules.push(...rule.mediaRules)
16
+ })
17
+ return rules;
18
+ }
19
+
20
+ addRule(rule: $CSSRule) {
21
+ this.rules.add(rule);
22
+ rule.ownerRule = this;
23
+ return this;
24
+ }
25
+ }
@@ -0,0 +1,23 @@
1
+ import type { $CSSDeclaration } from "#structure/$CSSDeclaration";
2
+ import { $CSSRule } from "#structure/$CSSRule";
3
+ import { _Array_from, _instanceof } from "amateras/lib/native";
4
+
5
+ export class $CSSStyleRule extends $CSSRule {
6
+ context: string[] = [];
7
+ declarations = new Map<string, $CSSDeclaration>();
8
+ className: string = '';
9
+ constructor(context: string[] = []) {
10
+ super();
11
+ this.context = context;
12
+ }
13
+
14
+ get css(): string {
15
+ return `${this.selector} { ${_Array_from(this.declarations).map(([_, dec]) => `${dec}`).join(' ')} }`
16
+ }
17
+
18
+ get selector() {
19
+ const ctx: string[][] = [];
20
+ this.context.forEach((part, i) => ctx.push(part.split(',').map(sel => ctx[i - 1] ? ctx[i - 1]!.map(prefix => `${prefix} ${sel.trim()}`) : [sel.trim()]).flat()))
21
+ return ctx.at(-1)?.join(', ')
22
+ }
23
+ }
@@ -0,0 +1,12 @@
1
+ export class $CSSVariable {
2
+ key: string;
3
+ value: string;
4
+ constructor(key: string, value: string) {
5
+ this.key = key;
6
+ this.value = value;
7
+ }
8
+
9
+ toString() {
10
+ return `var(--${this.key})`
11
+ }
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amateras",
3
- "version": "0.0.1",
3
+ "version": "0.1.1",
4
4
  "description": "Amateras is a DOM Utility library.",
5
5
  "module": "index.ts",
6
6
  "type": "module",
@@ -31,7 +31,12 @@
31
31
  "./lib/*": "./src/lib/*.ts",
32
32
  "./structure/*": "./src/structure/*.ts",
33
33
  "./html": "./ext/html/html.ts",
34
- "./css": "./ext/css/css.ts",
35
- "./css/*": "./ext/css/*.ts"
34
+ "./css": "./ext/css/src/index.ts"
35
+ },
36
+ "workspaces": [
37
+ "./ext/*"
38
+ ],
39
+ "peerDependencies": {
40
+ "@amateras/css": "./ext/css"
36
41
  }
37
- }
42
+ }
package/src/core.ts CHANGED
@@ -3,6 +3,7 @@ import { Signal } from "#structure/Signal";
3
3
  import { $Element } from "#node/$Element";
4
4
  import { $Node, type $NodeContentTypes } from '#node/$Node';
5
5
  import '#node/node';
6
+ import { _instanceof, _Object_defineProperty, _Object_entries, isFunction, isObject, isString, isUndefined } from '#lib/native';
6
7
 
7
8
  const tagNameMap: {[key: string]: Constructor<$Node>} = {}
8
9
  export function $<K extends (...args: any[]) => $Node>(fn: K, ...args: Parameters<K>): ReturnType<K>;
@@ -14,16 +15,16 @@ export function $<K extends Element>(element: K): $Element<K>;
14
15
  export function $<K extends keyof HTMLElementTagNameMap>(tagname: K): $Element<HTMLElementTagNameMap[K]>
15
16
  export function $(tagname: string): $Element<HTMLElement>
16
17
  export function $(resolver: string | HTMLElement | $Node | Function | TemplateStringsArray, ...args: any[]) {
17
- if (resolver instanceof $Node) return resolver;
18
- if (typeof resolver === 'string' && tagNameMap[resolver]) return new tagNameMap[resolver]();
19
- if (typeof resolver === 'function')
18
+ if (_instanceof(resolver, $Node)) return resolver;
19
+ if (isString(resolver) && tagNameMap[resolver]) return new tagNameMap[resolver]();
20
+ if (isFunction(resolver))
20
21
  if (resolver.prototype?.constructor) return resolver.prototype.constructor(...args);
21
22
  else return resolver(...args);
22
23
  if (resolver instanceof Array) {
23
24
  const iterate = args.values();
24
25
  return resolver.map(str => [str ?? undefined, iterate.next().value]).flat().filter(item => item);
25
26
  }
26
- if (resolver instanceof Node && resolver.$ instanceof $Node) return resolver.$;
27
+ if (_instanceof(resolver, Node) && _instanceof(resolver.$, $Node)) return resolver.$;
27
28
  return new $Element(resolver);
28
29
  }
29
30
 
@@ -35,15 +36,15 @@ export namespace $ {
35
36
  const signal = new Signal<T>(value);
36
37
  const signalFn = function (newValue?: T) {
37
38
  if (!arguments.length) return signal.value();
38
- if (newValue !== undefined) signal.value(newValue);
39
+ if (!isUndefined(newValue)) signal.value(newValue);
39
40
  return signalFn;
40
41
  }
41
- Object.defineProperty(signalFn, 'signal', { value: signal });
42
- if (value instanceof Object) {
43
- for (const [key, val] of Object.entries(value)) {
42
+ _Object_defineProperty(signalFn, 'signal', { value: signal });
43
+ if (isObject(value)) {
44
+ for (const [key, val] of _Object_entries(value)) {
44
45
  const val$ = $.signal(val);
45
46
  val$.signal.subscribe(newValue => { value[key as keyof typeof value] = newValue; signal.emit() });
46
- Object.defineProperty(signalFn, `${key}$`, {value: val$});
47
+ _Object_defineProperty(signalFn, `${key}$`, {value: val$});
47
48
  }
48
49
  }
49
50
  return signalFn as unknown as SignalFunction<T>
@@ -67,7 +68,7 @@ export namespace $ {
67
68
  subscribed = true;
68
69
  return result;
69
70
  }
70
- Object.defineProperty(computeFn, 'signal', { value: signalFn.signal });
71
+ _Object_defineProperty(computeFn, 'signal', { value: signalFn.signal });
71
72
  return computeFn as ComputeFunction<T>
72
73
  }
73
74
 
@@ -77,7 +78,11 @@ export namespace $ {
77
78
  }
78
79
 
79
80
  export function orArrayResolver<T>(item: OrArray<T>): T[] {
80
- return item instanceof Array ? item : [item];
81
+ return _instanceof(item, Array) ? item : [item];
82
+ }
83
+
84
+ export function span(content: string) {
85
+ return $('span').content(content);
81
86
  }
82
87
  }
83
88
  export type $ = typeof $;
package/src/lib/assign.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Signal } from "../structure/Signal";
2
+ import { _instanceof, _Object_defineProperty, isUndefined } from "./native";
2
3
 
3
4
  export function assign(target: any, {set, get, fn}: {
4
5
  set?: string[],
@@ -10,7 +11,7 @@ export function assign(target: any, {set, get, fn}: {
10
11
  }
11
12
  const list = [...filterAndMap('get', get), ...filterAndMap('set', set), ...filterAndMap('fn', fn)] as [string, string][];
12
13
  for (const [type, prop] of list) {
13
- Object.defineProperty(target.prototype, prop, {
14
+ _Object_defineProperty(target.prototype, prop, {
14
15
  ...(type === 'get' ? {
15
16
  get() { return this.node[prop as any] }
16
17
  } : {
@@ -19,8 +20,8 @@ export function assign(target: any, {set, get, fn}: {
19
20
  // set
20
21
  value: function (this, args: any) {
21
22
  if (!arguments.length) return this.node[prop];
22
- const set = (value: any) => value !== undefined && (this.node[prop] = value);
23
- if (args instanceof Signal) args = args.subscribe(set).value();
23
+ const set = (value: any) => !isUndefined(value) && (this.node[prop] = value);
24
+ if (_instanceof(args, Signal)) args = args.subscribe(set).value();
24
25
  set(args)
25
26
  return this;
26
27
  }
@@ -1,11 +1,12 @@
1
1
  import type { $Node } from "#node/$Node";
2
2
  import { assign } from "./assign";
3
+ import { _Object_entries, _Object_getOwnPropertyDescriptors } from "./native";
3
4
 
4
5
  export function assignHelper(targets: [object: Constructor<Node>, target: Constructor<$Node>, tagname?: string][]) {
5
6
  for (const [object, target, tagname] of targets) {
6
7
  const {set, get, fn} = { set: [] as string[], get: [] as string[], fn: [] as string[] }
7
8
  // assign native object properties to target
8
- for (const [prop, value] of Object.entries(Object.getOwnPropertyDescriptors(object.prototype))) {
9
+ for (const [prop, value] of _Object_entries(_Object_getOwnPropertyDescriptors(object.prototype))) {
9
10
  if (prop in target.prototype) continue;
10
11
  if (value.get && !value.set) get.push(prop);
11
12
  else if (value.value) fn.push(prop);
@@ -0,0 +1,34 @@
1
+ // Object
2
+ export const _Object_fromEntries = Object.fromEntries;
3
+ export const _Object_entries = Object.entries;
4
+ export const _Object_assign = Object.assign;
5
+ export const _Object_values = Object.values;
6
+ export const _Object_defineProperty = Object.defineProperty;
7
+ export const _Object_getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
8
+ // Array
9
+ export const _Array_from = Array.from;
10
+ // typeof
11
+ export function _typeof(target: any, type: 'string' | 'number' | 'object' | 'boolean' | 'function' | 'bigint' | 'symbol' | 'undefined') {
12
+ return typeof target === type;
13
+ }
14
+ export function isString(target: any): target is string {
15
+ return _typeof(target, 'string');
16
+ }
17
+ export function isNumber(target: any): target is number {
18
+ return _typeof(target, 'number')
19
+ }
20
+ export function isObject(target: any): target is object {
21
+ return _typeof(target, 'object')
22
+ }
23
+ export function isFunction(target: any): target is Function {
24
+ return _typeof(target, 'function')
25
+ }
26
+ export function isUndefined(target: any): target is undefined {
27
+ return _typeof(target, 'undefined')
28
+ }
29
+ export function isNull(target: any): target is null {
30
+ return target === null;
31
+ }
32
+ export function _instanceof<T>(target: any, instance: abstract new (...args: any[]) => T): target is T {
33
+ return target instanceof instance;
34
+ }
@@ -1,9 +1,11 @@
1
+ import { _Array_from } from "./native";
2
+
1
3
  const LOWER = 'abcdefghijklmnopqrstuvwxyz';
2
4
  const UPPER = LOWER.toUpperCase();
3
- export function randomId(options?: {length?: number, case?: 'any' | 'lower' | 'upper'}): string {
4
- options = {length: 5, case: 'any', ...options};
5
- const char = options.case === 'any' ? LOWER + UPPER : options.case === 'lower' ? LOWER : UPPER;
6
- return Array.from({length: options.length as number}, (_, i) => {
5
+ export function randomId(options?: {length?: number, lettercase?: 'any' | 'lower' | 'upper'}): string {
6
+ options = {length: 5, lettercase: 'any', ...options};
7
+ const char = options.lettercase === 'any' ? LOWER + UPPER : options.lettercase === 'lower' ? LOWER : UPPER;
8
+ return _Array_from({length: options.length as number}, (_, i) => {
7
9
  const rand = Math.round(Math.random() * char.length); return char[rand]
8
10
  }).join('');
9
11
  }
@@ -1,11 +1,12 @@
1
1
  import { Signal } from "#structure/Signal";
2
2
  import { $Node } from "#node/$Node";
3
+ import { _Array_from, _instanceof, _Object_entries, _Object_fromEntries, isUndefined } from "#lib/native";
3
4
 
4
5
  export class $Element<Ele extends Element = Element> extends $Node {
5
6
  listeners = new Map<Function, (event: Event) => void>;
6
7
  declare node: Ele
7
8
  constructor(resolver: Ele | string) {
8
- super(resolver instanceof Element ? resolver : document.createElement(resolver) as unknown as Ele)
9
+ super(_instanceof(resolver, Element) ? resolver : document.createElement(resolver) as unknown as Ele)
9
10
  //@ts-expect-error
10
11
  this.node.$ = this;
11
12
  }
@@ -13,10 +14,10 @@ export class $Element<Ele extends Element = Element> extends $Node {
13
14
  attr(): {[key: string]: string};
14
15
  attr(obj: {[key: string]: string | number | boolean | Signal<any>}): this;
15
16
  attr(obj?: {[key: string]: string | number | boolean | Signal<any>}) {
16
- if (!arguments.length) return Object.fromEntries(Array.from(this.node.attributes).map(attr => [attr.name, attr.value]));
17
- if (obj) for (let [key, value] of Object.entries(obj)) {
18
- const set = (value: any) => value !== undefined && this.node.setAttribute(key, `${value}`)
19
- if (value instanceof Signal) value = value.subscribe(set).value();
17
+ if (!arguments.length) return _Object_fromEntries(_Array_from(this.node.attributes).map(attr => [attr.name, attr.value]));
18
+ if (obj) for (let [key, value] of _Object_entries(obj)) {
19
+ const set = (value: any) => isUndefined(value) && this.node.setAttribute(key, `${value}`)
20
+ if (_instanceof(value, Signal)) value = value.subscribe(set).value();
20
21
  set(value);
21
22
  }
22
23
  return this;
package/src/node/$Node.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { _Array_from, _instanceof, isFunction, isNull, isObject, isUndefined } from "#lib/native";
1
2
  import { Signal } from "#structure/Signal";
2
3
 
3
4
  export class $Node {
@@ -9,14 +10,14 @@ export class $Node {
9
10
  }
10
11
 
11
12
  content(children: $NodeContentResolver<this>) {
12
- this.node.childNodes.forEach(node => node.remove());
13
+ _Array_from(this.node.childNodes).forEach(node => node.remove());
13
14
  return this.insert(children);
14
15
  }
15
16
 
16
17
  insert(resolver: $NodeContentResolver<this>, position = -1) {
17
- if (resolver instanceof Function) {
18
+ if (isFunction(resolver)) {
18
19
  const content = resolver(this);
19
- if (content instanceof Promise) content.then(content => $Node.insertChild(this.node, content, position))
20
+ if (_instanceof(content, Promise)) content.then(content => $Node.insertChild(this.node, content, position))
20
21
  else $Node.insertChild(this.node, content, position);
21
22
  } else $Node.insertChild(this.node, resolver, position);
22
23
  return this;
@@ -36,7 +37,7 @@ export class $Node {
36
37
  static insertChild(node: Node, children: OrArray<OrPromise<$NodeContentTypes>>, position = -1) {
37
38
  children = $.orArrayResolver(children);
38
39
  // get child node at position
39
- const positionChild = Array.from(node.childNodes).filter(node => node.nodeType !== node.TEXT_NODE).at(position);
40
+ const positionChild = _Array_from(node.childNodes).filter(node => node.nodeType !== node.TEXT_NODE).at(position);
40
41
  // insert node helper function for depend position
41
42
  const append = (child: Node | undefined | null) => {
42
43
  if (!child) return;
@@ -44,7 +45,7 @@ export class $Node {
44
45
  else node.insertBefore(child, position < 0 ? positionChild.nextSibling : positionChild);
45
46
  }
46
47
  // process nodes
47
- for (const child of children) if (child !== undefined) append($Node.processContent(child))
48
+ for (const child of children) !isUndefined(child) && append($Node.processContent(child))
48
49
  }
49
50
 
50
51
  static processContent(content: $NodeContentTypes): Node;
@@ -53,19 +54,19 @@ export class $Node {
53
54
  static processContent(content: OrPromise<$NodeContentTypes>): Node;
54
55
  static processContent(content: OrPromise<$NodeContentTypes | undefined | null>): Node | undefined | null
55
56
  static processContent(content: OrPromise<$NodeContentTypes | undefined | null>) {
56
- if (content === undefined) return undefined;
57
- if (content === null) return null;
57
+ if (isUndefined(content)) return;
58
+ if (isNull(content)) return content;
58
59
  // is $Element
59
- if (content instanceof $Node) return content.node;
60
+ if (_instanceof(content, $Node)) return content.node;
60
61
  // is Promise
61
- if (content instanceof Promise) {
62
+ if (_instanceof(content, Promise)) {
62
63
  const async = $('async').await(content, ($async, $child) => $async.replace($child));
63
64
  return async.node;
64
65
  }
65
66
  // is SignalFunction
66
- if (content instanceof Function && (content as $.SignalFunction<any>).signal instanceof Signal) {
67
+ if (isFunction(content) && _instanceof((content as $.SignalFunction<any>).signal ,Signal)) {
67
68
  const text = new Text();
68
- const set = (value: any) => text.textContent = value instanceof Object ? JSON.stringify(value) : value;
69
+ const set = (value: any) => text.textContent = isObject(value) ? JSON.stringify(value) : value;
69
70
  (content as $.SignalFunction<any>).signal.subscribe(set);
70
71
  set((content as $.SignalFunction<any>)());
71
72
  return text;
@@ -1,3 +1,5 @@
1
+ import { isUndefined } from "#lib/native";
2
+
1
3
  export class Signal<T> {
2
4
  #value: T;
3
5
  subscribers = new Set<(value: T) => void>();
@@ -15,7 +17,7 @@ export class Signal<T> {
15
17
  return this.#value;
16
18
  }
17
19
  if (resolver instanceof Function) this.value(resolver(this.#value));
18
- else if (resolver !== undefined) {
20
+ else if (!isUndefined(resolver)) {
19
21
  this.#value = resolver;
20
22
  this.emit();
21
23
  }
@@ -1,13 +0,0 @@
1
- import { $CSSRule } from "#css/$CSSRule";
2
-
3
- export class $CSSMediaRule extends $CSSRule {
4
- condition: string;
5
- constructor(condition: string) {
6
- super();
7
- this.condition = condition;
8
- }
9
-
10
- toString() {
11
- return `@media ${this.condition} { ${[...this.rules.values()].map(rule => rule.toString()).join('\n')} }`
12
- }
13
- }
@@ -1,7 +0,0 @@
1
- export abstract class $CSSRule {
2
- rules = new Set<$CSSRule>();
3
- constructor() {
4
- }
5
-
6
- abstract toString(): string;
7
- }
@@ -1,20 +0,0 @@
1
- import type { $CSSDeclaration } from "#css/$CSSDeclaration";
2
- import { $CSSRule } from "#css/$CSSRule";
3
-
4
- export class $CSSStyleRule extends $CSSRule {
5
- context: string[] = [];
6
- declarations = new Map<string, $CSSDeclaration>();
7
- className: string = '';
8
- constructor(context: string[] = []) {
9
- super();
10
- this.context = context;
11
- }
12
-
13
- toString() {
14
- return `${this.selector} { ${[...this.declarations.values()].map(dec => `${dec.property}: ${dec.value};`).join('\n')} }`
15
- }
16
-
17
- get selector() {
18
- return this.context.join(' ');
19
- }
20
- }
package/ext/css/css.ts DELETED
@@ -1,101 +0,0 @@
1
- import { $CSSDeclaration } from "#css/$CSSDeclaration";
2
- import { $CSSMediaRule } from "#css/$CSSMediaRule";
3
- import { $CSSRule } from "#css/$CSSRule";
4
- import { $CSSStyleRule } from "#css/$CSSStyleRule";
5
- import { randomId } from "#lib/randomId";
6
- import { $Element } from "#node/$Element";
7
-
8
- declare module '#core' {
9
- export namespace $ {
10
- export function css(options: $CSSOptions): $CSSStyleRule
11
- export function CSS(options: $CSSSelector | $CSSMediaSelector): void
12
- }
13
- }
14
-
15
- declare module '#node/$Element' {
16
- export interface $Element {
17
- css(...options: $CSSOptions[]): this;
18
- }
19
- }
20
-
21
- Object.defineProperty($, 'css', {
22
- value: function (options: $CSSOptions) {
23
- if (options instanceof $CSSRule) return options;
24
- const className = $CSS.generateClassName();
25
- const rule = $CSS.createStyleRule(options, [className]);
26
- rule.className = className;
27
- return $CSS.insertRule( rule );
28
- }
29
- })
30
-
31
- Object.defineProperty($, 'CSS', {
32
- value: function (options: $CSSSelector | $CSSMediaRule) {
33
- return Object.entries(options).map(([selector, declarations]) => {
34
- return $CSS.insertRule( $CSS.createRule(selector, declarations) );
35
- })
36
- }
37
- })
38
-
39
- Object.defineProperty($Element.prototype, 'css', {
40
- value: function (this: $Element, ...options: $CSSOptions[]) {
41
- options.forEach(options => {
42
- const rule = $.css(options);
43
- this.addClass(rule.context[0]?.slice(1) as string);
44
- })
45
- return this;
46
- }
47
- })
48
-
49
- export namespace $CSS {
50
- export const stylesheet = new CSSStyleSheet();
51
- const generatedIds = new Set<string>();
52
- document.adoptedStyleSheets.push($CSS.stylesheet);
53
- export function generateClassName(): string {
54
- const id = randomId();
55
- if (generatedIds.has(id)) return generateClassName();
56
- generatedIds.add(id);
57
- return `.${id}`;
58
- }
59
-
60
- export function createStyleRule<T extends $CSSRule>(options: T, context?: string[]): T;
61
- export function createStyleRule<T extends $CSSOptions>(options: T, context?: string[]): $CSSStyleRule;
62
- export function createStyleRule<T extends $CSSOptions>(options: T, context: string[] = []) {
63
- if (options instanceof $CSSRule) return options;
64
- const rule = new $CSSStyleRule(context);
65
- for (const [key, value] of Object.entries(options)) {
66
- if (value === undefined) continue;
67
- if (value instanceof Object) rule.rules.add( createRule(key, value, context) )
68
- else {
69
- const declaration = new $CSSDeclaration(key, value);
70
- rule.declarations.set(declaration.key, declaration);
71
- }
72
- }
73
- return rule;
74
- }
75
-
76
- export function createRule(selector: string, options: $CSSOptions, context: string[] = []) {
77
- if (selector.startsWith('@media')) return createMediaRule(selector.replace('@media ', ''), options, context);
78
- else return createStyleRule(options, [...context, selector],);
79
- }
80
-
81
- export function createMediaRule(key: string, options: $CSSOptions, context: string[] = []) {
82
- const rule = new $CSSMediaRule(key);
83
- rule.rules.add(createStyleRule(options, context));
84
- return rule;
85
- }
86
-
87
- export function insertRule(rule: $CSSRule) {
88
- if (rule instanceof $CSSStyleRule && !CSS.supports(`selector(${rule.selector})`)) return rule;
89
- $CSS.stylesheet.insertRule(rule.toString(), $CSS.stylesheet.cssRules.length);
90
- if (rule instanceof $CSSMediaRule) return;
91
- rule.rules.forEach(rule => insertRule(rule))
92
- return rule;
93
- }
94
- }
95
-
96
- type $CSSOptions = $CSSDeclarations | $CSSSelector | $CSSRule | $CSSMediaSelector;
97
- type $CSSDeclarations = { [key in keyof CSSStyleDeclaration]?: string | number }
98
- type $CSSSelector = { [key: string & {}]: $CSSOptions }
99
- type $CSSMediaSelector = { [key: `@${string}`]: $CSSOptions }
100
-
101
- console.debug(document.adoptedStyleSheets[0])