fscss 1.1.13 → 1.1.14
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 +20 -20
- package/example.fscss +14 -5
- package/lib/functions/all.js +156 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
1
|
# FSCSS
|
|
2
2
|
FSCSS (Figured Shorthand CSS) is a CSS preprocessor that extends CSS with shorthand utilities, variables, functions, and advanced transformations.
|
|
3
|
-
It works both in the browser and on the backend (Node.js).
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
---
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Features
|
|
11
10
|
|
|
12
11
|
Works in browser and backend (Node.js)
|
|
13
12
|
|
|
14
13
|
Supports:
|
|
15
14
|
|
|
16
|
-
- Variables ($var, str()) → define reusable values
|
|
17
|
-
|
|
18
|
-
-
|
|
15
|
+
- Variables ($var, str()) → define reusable values, str(boxBased, "..."), $var:...;
|
|
16
|
+
|
|
17
|
+
- Array Methods (@arr) → define array - https://github.com/fscss-ttr/FSCSS/blob/main/FSCSS_array_method.md
|
|
18
|
+
|
|
19
|
+
- Style Replacement (%n()) → shorthand repeated properties. %2(width, height[: 200px;])
|
|
20
|
+
|
|
19
21
|
- Repeat Function (rpt()) → repeat values quickly
|
|
20
22
|
|
|
21
23
|
- Copy Function (copy()) → copy parts of values
|
|
22
24
|
|
|
23
|
-
- String Extractor (@ext()) → extract substrings from values
|
|
25
|
+
- String Extractor (@ext()) → extract substrings from values.
|
|
24
26
|
|
|
25
|
-
- Drops / Shared Properties → reuse style groups
|
|
27
|
+
- Drops / Shared Properties → reuse style groups.
|
|
26
28
|
|
|
27
|
-
- Attribute Selectors → dynamic selectors
|
|
29
|
+
- Attribute Selectors → dynamic selectors. $(attribute:value){...}
|
|
28
30
|
|
|
29
31
|
- Keyframes ($(@keyframes …)) → generate animations easily
|
|
30
32
|
|
|
31
|
-
- Vendor Prefixing (-*) → auto add prefixes
|
|
32
|
-
|
|
33
|
-
- Function-based (@fun) → reusable function-like blocks
|
|
33
|
+
- Vendor Prefixing (-*) → auto add prefixes. -\*-webkit-text-stroke:...
|
|
34
34
|
|
|
35
|
-
-
|
|
35
|
+
- Function-based (@fun) → reusable function-like blocks. @fun(name){...}
|
|
36
36
|
|
|
37
|
-
- Random Function (@random()) → random values at runtime
|
|
37
|
+
- Random Function (@random()) → random values at runtime. @random([.,.,...]) or using array!.randint instead
|
|
38
38
|
|
|
39
|
-
- Number Calculation (num()) → evaluate math expressions
|
|
39
|
+
- Number Calculation (num()) → evaluate math expressions. num(4+5)
|
|
40
40
|
|
|
41
|
-
- Import (@import) → include external FSCSS files
|
|
41
|
+
- Import (@import) → include external FSCSS files. @import(exec(...))
|
|
42
42
|
|
|
43
43
|
- @event → event-based styling logic
|
|
44
44
|
|
|
45
|
-
- exec() → debugging and runtime helpers
|
|
45
|
+
- exec() → debugging and runtime helpers. exec(_log, "...")
|
|
46
46
|
|
|
47
47
|
- Variable fallback chain (property: $/var || fallback;)
|
|
48
48
|
|
|
@@ -50,7 +50,7 @@ Supports:
|
|
|
50
50
|
### Example
|
|
51
51
|
```css
|
|
52
52
|
/* FSCSS, Animation compact */
|
|
53
|
-
$(@keyframes trans, .box .card &[3s
|
|
53
|
+
$(@keyframes trans, .box, .card &[3s ase-in infinite]) {
|
|
54
54
|
from {
|
|
55
55
|
%2(width, height [: 0;])
|
|
56
56
|
background: red;
|
|
@@ -62,7 +62,7 @@ $(@keyframes trans, .box .card &[3s ease-in infinite]) {
|
|
|
62
62
|
}
|
|
63
63
|
```
|
|
64
64
|
|
|
65
|
-
###
|
|
65
|
+
### Installation
|
|
66
66
|
|
|
67
67
|
`npm install -g fscss`
|
|
68
68
|
|
|
@@ -72,7 +72,7 @@ Or locally to your project:
|
|
|
72
72
|
|
|
73
73
|
**Browser CDN**
|
|
74
74
|
```html
|
|
75
|
-
<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.
|
|
75
|
+
<script src="https://cdn.jsdelivr.net/npm/fscss@1.1.14/exec.min.js" defer></script>
|
|
76
76
|
```
|
|
77
77
|
Usage
|
|
78
78
|
|
|
@@ -86,7 +86,7 @@ Or import inside a style block:
|
|
|
86
86
|
@import(exec(style.fscss))
|
|
87
87
|
</style>
|
|
88
88
|
```
|
|
89
|
-
|
|
89
|
+
**Async or defer is required for script loading.**
|
|
90
90
|
|
|
91
91
|
|
|
92
92
|
---
|
package/example.fscss
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
@import(exec(_init themes))
|
|
2
2
|
@import(exec(style.fscss).pick(body))
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
@arr colors[#1E2783, #8C29B2, #C41348]
|
|
4
|
+
$colors: @arr.colors!;
|
|
5
|
+
div{
|
|
6
|
+
background: @event.theme(forest);
|
|
7
|
+
%2(width, height[: 200px;])
|
|
8
|
+
tr Shape: @event.shape(star);
|
|
9
|
+
}
|
|
10
|
+
.box{
|
|
11
|
+
background: radial-gradient(40deg, $colors.list);
|
|
12
|
+
}
|
|
13
|
+
.box-b{
|
|
14
|
+
background: radial-gradient(40deg, $colors.reverse);
|
|
15
|
+
}
|
|
16
|
+
exec(_log, "Hello World!")
|
package/lib/functions/all.js
CHANGED
|
@@ -260,10 +260,18 @@ function procExC(css) {
|
|
|
260
260
|
|
|
261
261
|
return modifiedCSS.trim();
|
|
262
262
|
}
|
|
263
|
+
|
|
263
264
|
function initlibraries(css){
|
|
264
265
|
css = css.replace(/exec\(\s*_init\sisjs\s*\)/g, "exec(https://cdn.jsdelivr.net/gh/fscss-ttr/FSCSS@main/xf/styles/isjs.fscss)");
|
|
265
266
|
css = css.replace(/exec\(\s*_init\sthemes\s*\)/g, "exec(https://cdn.jsdelivr.net/gh/fscss-ttr/FSCSS@main/xf/styles/trshapes.fthemes.fscss)")
|
|
266
267
|
css = css.replace(/exec\(_init\sarray1to500\s*\)/g, "exec(https://cdn.jsdelivr.net/gh/fscss-ttr/FSCSS@main/xf/styles/1to500.fscss)");
|
|
268
|
+
css = css.replace(/exec\(_init\s+([\w\d\._—\-\%\*\+\&\$\=]+)(?:\/([\w\-]+))?\s*\)/g, (match, impName, impType)=>{
|
|
269
|
+
if(!impType){
|
|
270
|
+
//`
|
|
271
|
+
return `exec(https://cdn.jsdelivr.net/gh/fscss-ttr/FSCSS@main/xf/styles/${impName}.fscss)`;
|
|
272
|
+
}
|
|
273
|
+
return `exec(https://cdn.jsdelivr.net/gh/fscss-ttr/FSCSS@main/xf/styles/${impName}.${impType})`;
|
|
274
|
+
});
|
|
267
275
|
return css;
|
|
268
276
|
}
|
|
269
277
|
function procVar(vcss) {
|
|
@@ -453,6 +461,7 @@ function procRan(input) {
|
|
|
453
461
|
}
|
|
454
462
|
});
|
|
455
463
|
}
|
|
464
|
+
|
|
456
465
|
function procArr(input) {
|
|
457
466
|
// 1. Parse array declarations
|
|
458
467
|
const arrayDeclarationRegex = /@arr\(?\s*([\w\-_—0-9]+)\)?\[([^\]]+)\]\)?/g;
|
|
@@ -465,6 +474,99 @@ function procArr(input) {
|
|
|
465
474
|
|
|
466
475
|
let output = input;
|
|
467
476
|
|
|
477
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:\!\s*\+\s*\[([^\]]+)?\])/g, (match, arrName, newArr) => {
|
|
478
|
+
const arr = arraysExfscss[arrName];
|
|
479
|
+
if (!arr) {
|
|
480
|
+
console.warn(`fscss[@arr] Warning: Array '${arrName}' not found.`);
|
|
481
|
+
return match;
|
|
482
|
+
}
|
|
483
|
+
if (!newArr) {
|
|
484
|
+
console.warn(
|
|
485
|
+
`[FSCSS Warning] @arr push failed → Invalid or empty value at "${match}"`
|
|
486
|
+
);
|
|
487
|
+
return match;
|
|
488
|
+
}
|
|
489
|
+
newItems = newArr.split(',').map(item => item.trim());
|
|
490
|
+
arraysExfscss[arrName].push(...newItems);
|
|
491
|
+
return "";
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:\!\s*\-\s*\[([\d\w\-_—\s]+)?\])/g, (match, arrName, ind) => {
|
|
495
|
+
const arr = arraysExfscss[arrName];
|
|
496
|
+
if (!arr) {
|
|
497
|
+
console.warn(`fscss[@arr] Warning: Array '${arrName}' not found.`);
|
|
498
|
+
return match;
|
|
499
|
+
}
|
|
500
|
+
ind = Number(ind?.trim());
|
|
501
|
+
if (!ind||ind<1||!Number(ind)) {
|
|
502
|
+
console.warn(
|
|
503
|
+
`[FSCSS Warning] @arr splice failed → Invalid or empty index at "${match}"`
|
|
504
|
+
);
|
|
505
|
+
return match;
|
|
506
|
+
}
|
|
507
|
+
if(ind>arr.length){
|
|
508
|
+
console.warn(
|
|
509
|
+
`[FSCSS Warning] @arr → @arr.${arrName}[${ind}] is undefined at "${match}"`);
|
|
510
|
+
return "";
|
|
511
|
+
}
|
|
512
|
+
ind = (ind-1);
|
|
513
|
+
arr.splice(ind,1);
|
|
514
|
+
return "";
|
|
515
|
+
})
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:\!\s*\.(length|last|reverse|first|list|indices|randint|segment|sum|unique|sort|shuffle|min|max))/g, (match, arrName, obj) => {
|
|
519
|
+
const arr = arraysExfscss[arrName];
|
|
520
|
+
if (!arr) {
|
|
521
|
+
console.warn(`fscss[@arr] Warning: Array '${arrName}' not found.`);
|
|
522
|
+
return match;
|
|
523
|
+
}
|
|
524
|
+
if(obj){
|
|
525
|
+
if (obj==="length") {
|
|
526
|
+
return arr.length;
|
|
527
|
+
}
|
|
528
|
+
if(obj==="first"){
|
|
529
|
+
return arr[0];
|
|
530
|
+
}
|
|
531
|
+
if (obj==="last") {
|
|
532
|
+
return arr.at(-1);
|
|
533
|
+
}
|
|
534
|
+
if (obj==="indices") {
|
|
535
|
+
return Array(arr.length).fill().map((_, i)=>(i+1)*1);
|
|
536
|
+
}
|
|
537
|
+
if (obj==="list") {
|
|
538
|
+
return arr.join(',');
|
|
539
|
+
}
|
|
540
|
+
if (obj==="reverse") {
|
|
541
|
+
return arr.toReversed().join(',');
|
|
542
|
+
}
|
|
543
|
+
if (obj==="randint") {
|
|
544
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
545
|
+
}
|
|
546
|
+
if(obj==="segment") {
|
|
547
|
+
return arr.map(u => `[${u}]`).join('')
|
|
548
|
+
}
|
|
549
|
+
if (obj === "unique") {
|
|
550
|
+
return [...new Set(arr)].join(',');
|
|
551
|
+
}
|
|
552
|
+
if (obj === "sort") {
|
|
553
|
+
return arr.slice().sort().join(',');
|
|
554
|
+
}
|
|
555
|
+
if (obj === "shuffle") {
|
|
556
|
+
return arr.slice().sort(() => Math.random() - 0.5).join(',');
|
|
557
|
+
}
|
|
558
|
+
if (obj === "sum") {
|
|
559
|
+
return arr.reduce((a, b) => a + Number(b), 0);
|
|
560
|
+
}
|
|
561
|
+
if (obj === "min") {
|
|
562
|
+
return Math.min(...arr.map(Number));
|
|
563
|
+
}
|
|
564
|
+
if (obj === "max") {
|
|
565
|
+
return Math.max(...arr.map(Number));
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
})
|
|
569
|
+
|
|
468
570
|
// 2. Process loops using @arr.name[]
|
|
469
571
|
output = output.replace(/([^\{\}]+)\{\s*([^}]*@arr\.([\w\-_—0-9]+)\[\][^}]*)\s*\}/g,
|
|
470
572
|
(fullMatch, selector, content, arrayName) => {
|
|
@@ -493,8 +595,49 @@ function procArr(input) {
|
|
|
493
595
|
return arr[idx] !== undefined ? arr[idx] : fullMatch;
|
|
494
596
|
});
|
|
495
597
|
|
|
598
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:!\s*\.unit)(?:\(([^)]*)\))/g,
|
|
599
|
+
(fullMatch, arrayName, pl) => {
|
|
600
|
+
const arr = arraysExfscss[arrayName];
|
|
601
|
+
if (!arr) {
|
|
602
|
+
console.warn(`fscss[@arr] Warning: Array '${arrayName}' not found for direct access.`);
|
|
603
|
+
return fullMatch;
|
|
604
|
+
}
|
|
605
|
+
const sep = (pl !== undefined && pl !== "") ? pl : ' ';
|
|
606
|
+
return arr.map(u=>`${u+sep}`).join(',');
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:!\s*\.prefix)(?:\(([^)]*)\))/g,
|
|
610
|
+
(fullMatch, arrayName, pl) => {
|
|
611
|
+
const arr = arraysExfscss[arrayName];
|
|
612
|
+
if (!arr) {
|
|
613
|
+
console.warn(`fscss[@arr] Warning: Array '${arrayName}' not found for direct access.`);
|
|
614
|
+
return fullMatch;
|
|
615
|
+
}
|
|
616
|
+
const sep = (pl !== undefined && pl !== "") ? pl : ' ';
|
|
617
|
+
return arr.map(u=>`${sep+u}`).join(',');
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:!\s*\.surround)(?:\(([^)]+)\))/g,
|
|
623
|
+
(fullMatch, arrayName, sur) => {
|
|
624
|
+
const arr = arraysExfscss[arrayName];
|
|
625
|
+
if (!arr) {
|
|
626
|
+
console.warn(`fscss[@arr] Warning: Array '${arrayName}' not found for direct access.`);
|
|
627
|
+
return fullMatch;
|
|
628
|
+
}
|
|
629
|
+
if(!sur||sur===undefined||sur===""||!sur.includes(",")){
|
|
630
|
+
console.warn(
|
|
631
|
+
`[FSCSS Warning] @arr surround failed → Invalid or empty value at "${fullMatch}"`);
|
|
632
|
+
return fullMatch;
|
|
633
|
+
}
|
|
634
|
+
surArr = sur.split(',');
|
|
635
|
+
return arr.map(u=>`${surArr[0]+u+surArr.at(-1)}`).join(' ');
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
|
|
496
639
|
// 4. Direct array access: @arr.name or @arr.name(separator)
|
|
497
|
-
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:\(([^)]*)\))
|
|
640
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(?:!\s*\.join)?(?:\(([^)]*)\))/g,
|
|
498
641
|
(fullMatch, arrayName, separator) => {
|
|
499
642
|
const arr = arraysExfscss[arrayName];
|
|
500
643
|
if (!arr) {
|
|
@@ -504,8 +647,18 @@ function procArr(input) {
|
|
|
504
647
|
const sep = (separator !== undefined && separator !== "") ? separator : ' ';
|
|
505
648
|
return arr.join(sep);
|
|
506
649
|
});
|
|
507
|
-
|
|
508
|
-
|
|
650
|
+
output = output.replace(/@arr\.([\w\-_—0-9]+)(!)?/g, (match, arrName, fos)=>{
|
|
651
|
+
const arr = arraysExfscss[arrName];
|
|
652
|
+
if (!arr) {
|
|
653
|
+
console.warn(`fscss[@arr] Warning: Array '${arrName}' not found for direct access.`);
|
|
654
|
+
return match;
|
|
655
|
+
}
|
|
656
|
+
if(fos){
|
|
657
|
+
return match;
|
|
658
|
+
}
|
|
659
|
+
return arr.join(' ');
|
|
660
|
+
})
|
|
661
|
+
// Clean up array declarations
|
|
509
662
|
return output
|
|
510
663
|
.replace(arrayDeclarationRegex, '')
|
|
511
664
|
.replace(/\n{3,}/g, '\n\n')
|