chocola 1.2.6 → 1.3.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.
- package/.gitattributes +2 -0
- package/LICENSE +2 -2
- package/README.md +11 -12
- package/compiler/component-processor.js +34 -9
- package/compiler/pipeline.js +2 -2
- package/dev/index.js +69 -4
- package/package.json +14 -2
- package/types/index.js +135 -0
package/.gitattributes
ADDED
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2026 Sad Gabi
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Chocola is a lightweight, reactive component-based web framework that brings sim
|
|
|
16
16
|
- **🔌 Component Lifecycle API** - Public APIs for mounting, manipulating, and removing components
|
|
17
17
|
- **📦 Built-in Bundler** - Automatic compilation and optimization
|
|
18
18
|
- **🔥 Hot Reload Development** - See changes instantly with the dev server
|
|
19
|
-
- **🎨 Template Syntax** - Clean HTML templates with
|
|
19
|
+
- **🎨 Template Syntax** - Clean HTML templates with `{}` and `&{}` interpolation
|
|
20
20
|
- **⚙️ Zero Config** - Works out of the box with sensible defaults
|
|
21
21
|
|
|
22
22
|
## 🚀 Quick Start
|
|
@@ -70,14 +70,14 @@ Create a `chocola.config.json` file:
|
|
|
70
70
|
### 1. Define Your HTML Template
|
|
71
71
|
|
|
72
72
|
> NOTE: Reactivity, component APIs and global variables are not implemented yet.
|
|
73
|
-
> Any of
|
|
73
|
+
> Any of these features displayed here are for future references and may be modified.
|
|
74
74
|
|
|
75
|
-
Create `src/lib/html/counter.
|
|
75
|
+
Create `src/lib/html/counter.html`:
|
|
76
76
|
|
|
77
77
|
```html
|
|
78
78
|
<div class="counter">
|
|
79
|
-
<h2
|
|
80
|
-
<!-- Use &
|
|
79
|
+
<h2>{ctx.title}</h2>
|
|
80
|
+
<!-- Use & to set reactivity -->
|
|
81
81
|
<p>Count: &{sfx.count}</p>
|
|
82
82
|
<button class="increment">+</button>
|
|
83
83
|
<button class="decrement">-</button>
|
|
@@ -90,7 +90,7 @@ Create `src/lib/Counter.js`:
|
|
|
90
90
|
|
|
91
91
|
```javascript
|
|
92
92
|
import { lib } from "chocola";
|
|
93
|
-
import HTML from "./html/counter.
|
|
93
|
+
import HTML from "./html/counter.html";
|
|
94
94
|
|
|
95
95
|
function RUNTIME(self, ctx) {
|
|
96
96
|
// Acces to component effects
|
|
@@ -154,8 +154,7 @@ In your `src/index.html`:
|
|
|
154
154
|
</head>
|
|
155
155
|
<body>
|
|
156
156
|
<app>
|
|
157
|
-
|
|
158
|
-
<Counter ctx.title="My Counter" sfx.&initialCount="0"></Counter>
|
|
157
|
+
<Counter ctx.title="My Counter" sfx.initialCount="0"></Counter>
|
|
159
158
|
</app>
|
|
160
159
|
</body>
|
|
161
160
|
</html>
|
|
@@ -165,7 +164,7 @@ In your `src/index.html`:
|
|
|
165
164
|
|
|
166
165
|
### Template (`body`)
|
|
167
166
|
- Standard HTML with template variables
|
|
168
|
-
- **Static context**:
|
|
167
|
+
- **Static context**: `{ctx.propertyName}`, `{sfx.propertyName}` - rendered once at initialization
|
|
169
168
|
- **Reactive state**: `&{sfx.propertyName}` - automatically updates on change
|
|
170
169
|
- Clean separation of markup and logic
|
|
171
170
|
|
|
@@ -260,7 +259,7 @@ Share state across your entire application:
|
|
|
260
259
|
// In any component
|
|
261
260
|
import * as globals from "path/to/globals.js";
|
|
262
261
|
|
|
263
|
-
function RUNTIME(self, ctx
|
|
262
|
+
function RUNTIME(self, ctx) {
|
|
264
263
|
// Set global variables
|
|
265
264
|
globals.userTheme = "dark";
|
|
266
265
|
globals.notifications = [];
|
|
@@ -280,7 +279,7 @@ import { lib } from "chocola";
|
|
|
280
279
|
import Counter from "./lib/Counter.js";
|
|
281
280
|
|
|
282
281
|
// Mount a component programmatically in RUNTIME and/or EFFECTS
|
|
283
|
-
function RUNTIME(self
|
|
282
|
+
function RUNTIME(self, ctx) {
|
|
284
283
|
const counterInstance = lib.mount(Counter)
|
|
285
284
|
.defCtx({
|
|
286
285
|
title: "Dynamic Counter",
|
|
@@ -325,7 +324,7 @@ import { fileURLToPath } from "url";
|
|
|
325
324
|
const __filename = fileURLToPath(import.meta.url);
|
|
326
325
|
const __dirname = path.dirname(__filename);
|
|
327
326
|
|
|
328
|
-
dev.server(__dirname
|
|
327
|
+
dev.server(__dirname);
|
|
329
328
|
```
|
|
330
329
|
|
|
331
330
|
Run:
|
|
@@ -17,7 +17,8 @@ export function processComponentElement(
|
|
|
17
17
|
loadedComponents,
|
|
18
18
|
runtimeChunks,
|
|
19
19
|
compIdColl,
|
|
20
|
-
letterState
|
|
20
|
+
letterState,
|
|
21
|
+
runtimeMap
|
|
21
22
|
) {
|
|
22
23
|
const tagName = element.tagName.toLowerCase();
|
|
23
24
|
const compName = tagName + ".js";
|
|
@@ -28,7 +29,7 @@ export function processComponentElement(
|
|
|
28
29
|
|
|
29
30
|
if (instance && instance.body) {
|
|
30
31
|
let body = instance.body;
|
|
31
|
-
body = body.replace(
|
|
32
|
+
body = body.replace(/\{ctx\.(\w+)\}/g, (_, key) => ctx[key] || "");
|
|
32
33
|
const fragment = JSDOM.fragment(body);
|
|
33
34
|
const firstChild = fragment.firstChild;
|
|
34
35
|
|
|
@@ -38,14 +39,37 @@ export function processComponentElement(
|
|
|
38
39
|
firstChild.setAttribute("chid", compId);
|
|
39
40
|
|
|
40
41
|
let script = instance.script && instance.script.toString();
|
|
41
|
-
const letter = getNextLetter(letterState);
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
const ctxRegex = /ctx\s*=\s*({.*?})/;
|
|
44
|
+
const ctxMatch = script.match(ctxRegex);
|
|
45
|
+
let runtimeCtx = {};
|
|
46
|
+
if (ctxMatch) {
|
|
47
|
+
try {
|
|
48
|
+
runtimeCtx = JSON.parse(ctxMatch[1].replace(/(\w+):/g, '"$1":'));
|
|
49
|
+
} catch (e) {
|
|
50
|
+
runtimeCtx = {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
let ctxDef = "";
|
|
54
|
+
for (const [key, value] of Object.entries(runtimeCtx)) {
|
|
55
|
+
ctxDef += `ctx.${key} = ctx.${key}||${JSON.stringify(value)};\n`;
|
|
56
|
+
}
|
|
57
|
+
script = script.replace(ctxRegex, "ctx");
|
|
58
|
+
script = script.replace(/RUNTIME\([^)]*\)\s*{/, match => match + "\n" + ctxDef);
|
|
44
59
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
60
|
+
// Determine or create a single runtime function per component
|
|
61
|
+
let letterEntry = runtimeMap && runtimeMap.get(compName);
|
|
62
|
+
let letter;
|
|
63
|
+
if (!letterEntry) {
|
|
64
|
+
letter = getNextLetter(letterState);
|
|
65
|
+
script = script.replace(/RUNTIME/g, `${letter}RUNTIME`);
|
|
66
|
+
runtimeChunks.push(script);
|
|
67
|
+
runtimeMap && runtimeMap.set(compName, { letter });
|
|
68
|
+
} else {
|
|
69
|
+
letter = letterEntry.letter;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
runtimeChunks.push(`${letter}RUNTIME(document.querySelector('[chid="${compId}"]'), ${JSON.stringify(ctx)});`);
|
|
49
73
|
}
|
|
50
74
|
}
|
|
51
75
|
element.replaceWith(fragment);
|
|
@@ -69,9 +93,10 @@ export function processAllComponents(appElements, loadedComponents) {
|
|
|
69
93
|
const runtimeChunks = [];
|
|
70
94
|
const compIdColl = [];
|
|
71
95
|
const letterState = { value: null };
|
|
96
|
+
const runtimeMap = new Map();
|
|
72
97
|
|
|
73
98
|
appElements.forEach(el => {
|
|
74
|
-
processComponentElement(el, loadedComponents, runtimeChunks, compIdColl, letterState);
|
|
99
|
+
processComponentElement(el, loadedComponents, runtimeChunks, compIdColl, letterState, runtimeMap);
|
|
75
100
|
});
|
|
76
101
|
|
|
77
102
|
const runtimeScript = runtimeChunks.join("\n");
|
package/compiler/pipeline.js
CHANGED
|
@@ -7,8 +7,8 @@ import path from "path";
|
|
|
7
7
|
// ===== Component Loading =====
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Discovers and loads all components from a library directory
|
|
11
|
-
* Components are JavaScript files that start with an uppercase letter
|
|
10
|
+
* Discovers and loads all components from a library directory.
|
|
11
|
+
* Components are JavaScript files that start with an uppercase letter.
|
|
12
12
|
* They must have a default export that is a function
|
|
13
13
|
* @param {import("node:fs").PathLike} libDir - Directory containing component files
|
|
14
14
|
* @returns {Promise<{
|
package/dev/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from "fs";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import compile from "../compiler/index.js";
|
|
6
|
+
import { loadConfig, resolvePaths } from "../compiler/config.js";
|
|
6
7
|
import { getChocolaConfig } from "../utils.js";
|
|
7
8
|
|
|
8
9
|
export async function serve(__rootdir) {
|
|
@@ -14,8 +15,12 @@ export async function serve(__rootdir) {
|
|
|
14
15
|
port: 3000,
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
let lastBuildTime = Date.now();
|
|
19
|
+
|
|
20
|
+
const fullConfig = await getChocolaConfig(__rootdir);
|
|
21
|
+
const config = await loadConfig(__rootdir);
|
|
22
|
+
const paths = resolvePaths(__rootdir, config);
|
|
23
|
+
const devConfig = fullConfig.dev;
|
|
19
24
|
|
|
20
25
|
if (devConfig.hostname) { __config.hostname = devConfig.hostname }
|
|
21
26
|
else { console.warn(chalk.bold.yellow("WARNING!"), `hostname not defined in chocola.config.json file: using default ${__config.hostname} hostname.`) }
|
|
@@ -23,7 +28,42 @@ export async function serve(__rootdir) {
|
|
|
23
28
|
if (devConfig.port) { __config.port = devConfig.port }
|
|
24
29
|
else { console.warn(chalk.bold.yellow("WARNING!"), `port not defined in chocola.config.json file: using default ${__config.port} port.`) }
|
|
25
30
|
|
|
31
|
+
const srcDir = paths.src;
|
|
32
|
+
const componentsDir = paths.components;
|
|
33
|
+
|
|
34
|
+
let compileTimeout;
|
|
35
|
+
const scheduleRecompile = () => {
|
|
36
|
+
clearTimeout(compileTimeout);
|
|
37
|
+
compileTimeout = setTimeout(async () => {
|
|
38
|
+
try {
|
|
39
|
+
await compile(__rootdir, { isHotReload: true });
|
|
40
|
+
lastBuildTime = Date.now();
|
|
41
|
+
console.log(chalk.green("✓"), "Hot reload: compiled successfully");
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(chalk.red("✗"), "Hot reload compilation failed:", error.message);
|
|
44
|
+
}
|
|
45
|
+
}, 300);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
fs.watch(srcDir, { recursive: true }, (eventType, filename) => {
|
|
50
|
+
if (filename && !filename.includes("node_modules")) {
|
|
51
|
+
scheduleRecompile();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
fs.watch(componentsDir, { recursive: true }, (eventType, filename) => {
|
|
55
|
+
if (filename && !filename.includes("node_modules")) {
|
|
56
|
+
scheduleRecompile();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
26
60
|
const server = http.createServer((req, res) => {
|
|
61
|
+
if (req.url === "/api/hot-reload") {
|
|
62
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
63
|
+
res.end(JSON.stringify({ buildTime: lastBuildTime }));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
27
67
|
let filePath = path.join(
|
|
28
68
|
__outdir,
|
|
29
69
|
req.url === "/" ? "index.html" : req.url
|
|
@@ -78,8 +118,33 @@ export async function serve(__rootdir) {
|
|
|
78
118
|
res.end("Error interno: " + error.code);
|
|
79
119
|
}
|
|
80
120
|
} else {
|
|
81
|
-
|
|
82
|
-
|
|
121
|
+
if (extname === ".html" || extname === ".htm") {
|
|
122
|
+
const hotReloadScript = `
|
|
123
|
+
<script>
|
|
124
|
+
(function() {
|
|
125
|
+
let lastBuildTime = ${lastBuildTime};
|
|
126
|
+
setInterval(async () => {
|
|
127
|
+
try {
|
|
128
|
+
const res = await fetch('/api/hot-reload');
|
|
129
|
+
const data = await res.json();
|
|
130
|
+
if (data.buildTime > lastBuildTime) {
|
|
131
|
+
lastBuildTime = data.buildTime;
|
|
132
|
+
console.log('[Hot Reload] Changes detected, reloading...');
|
|
133
|
+
window.location.reload();
|
|
134
|
+
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
console.error('[Hot Reload] Check failed:', e);
|
|
137
|
+
}
|
|
138
|
+
}, 1000);
|
|
139
|
+
})();
|
|
140
|
+
</script>`;
|
|
141
|
+
const htmlWithReload = content.toString().replace('</body>', hotReloadScript + '</body>');
|
|
142
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
143
|
+
res.end(htmlWithReload, "utf-8");
|
|
144
|
+
} else {
|
|
145
|
+
res.writeHead(200, { "Content-Type": contentType });
|
|
146
|
+
res.end(content, "utf-8");
|
|
147
|
+
}
|
|
83
148
|
}
|
|
84
149
|
});
|
|
85
150
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chocola",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Chocola pipeline for web apps.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web",
|
|
@@ -11,13 +11,25 @@
|
|
|
11
11
|
"components",
|
|
12
12
|
"ui"
|
|
13
13
|
],
|
|
14
|
-
"
|
|
14
|
+
"homepage": "https://github.com/sad-gabi/chocola#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/sad-gabi/chocola/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/sad-gabi/chocola.git"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
15
23
|
"author": "SadGabi",
|
|
16
24
|
"type": "module",
|
|
17
25
|
"main": "index.js",
|
|
18
26
|
"scripts": {
|
|
19
27
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
20
28
|
},
|
|
29
|
+
"exports": {
|
|
30
|
+
".": "./index.js",
|
|
31
|
+
"./types": "./types/index.js"
|
|
32
|
+
},
|
|
21
33
|
"dependencies": {
|
|
22
34
|
"chalk": "^5.6.2",
|
|
23
35
|
"js-beautify": "^1.15.4",
|
package/types/index.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
const iconsType = "home" | "search" | "menu" | "settings" | "favorite" | "account_circle" | "shopping_cart" | "notifications" | "info" | "help" | "exit_to_app" | "check_circle" | "close" | "edit" | "delete" | "add" | "arrow_back" | "arrow_forward" | "play_arrow" | "pause" | "stop" | "camera_alt" | "photo" | "alarm" | "event" | "attach_file" | "print" | "share" | "cloud" | "cloud_upload" | "cloud_download" | "lock" | "lock_open" | "visibility" | "visibility_off" | "phone" | "email" | "map" | "place" | "directions" | "train" | "directions_car" | "directions_bike" | "school" | "work" | "lightbulb" | "battery_full" | "battery_std" | "wifi" | "bluetooth";
|
|
2
|
+
const iconsArray = [
|
|
3
|
+
"home", "search", "menu", "settings", "favorite", "account_circle",
|
|
4
|
+
"shopping_cart", "notifications", "info", "help", "exit_to_app",
|
|
5
|
+
"check_circle", "close", "edit", "delete", "add", "arrow_back",
|
|
6
|
+
"arrow_forward", "play_arrow", "pause", "stop", "camera_alt",
|
|
7
|
+
"photo", "alarm", "event", "attach_file", "print", "share",
|
|
8
|
+
"cloud", "cloud_upload", "cloud_download", "lock", "lock_open",
|
|
9
|
+
"visibility", "visibility_off", "phone", "email", "map", "place",
|
|
10
|
+
"directions", "train", "directions_car", "directions_bike", "school",
|
|
11
|
+
"work", "lightbulb", "battery_full", "battery_std", "wifi", "bluetooth"
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* An instrinsic object that contains chocola types
|
|
15
|
+
*/
|
|
16
|
+
const ct = {};
|
|
17
|
+
/**
|
|
18
|
+
* Creates an interface for the component static context
|
|
19
|
+
* @param {object} ctxInterface
|
|
20
|
+
*/
|
|
21
|
+
ct.defCtx = (ctxInterface) => {
|
|
22
|
+
if (!ctxInterface) return undefined;
|
|
23
|
+
if (typeof ctxInterface !== "object") return;
|
|
24
|
+
return ctxInterface;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
ct.Number = class Number {
|
|
28
|
+
/**
|
|
29
|
+
* @param {number} value
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
constructor(value) {
|
|
33
|
+
if (!value) return undefined;
|
|
34
|
+
if (typeof value !== "number") return;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* @param {number} min
|
|
39
|
+
* @param {number} max
|
|
40
|
+
* @returns {number}
|
|
41
|
+
*/
|
|
42
|
+
clamp(min, max) {
|
|
43
|
+
return Math.min(Math.max(this.value, min), max);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* @param {number} min
|
|
47
|
+
* @returns {number}
|
|
48
|
+
*/
|
|
49
|
+
min(min) {
|
|
50
|
+
return Math.min(this.value, min);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @param {number} max
|
|
54
|
+
* @returns {number}
|
|
55
|
+
*/
|
|
56
|
+
max(max) {
|
|
57
|
+
return Math.max(this.value, max);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @param {number} value
|
|
62
|
+
*/
|
|
63
|
+
ct.Float = (value) => {
|
|
64
|
+
if (!value) return undefined;
|
|
65
|
+
if (Number.isInteger(value)) return;
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* @param {number} value
|
|
70
|
+
*/
|
|
71
|
+
ct.Int = (value) => {
|
|
72
|
+
if (!value) return undefined;
|
|
73
|
+
if (!Number.isInteger(value)) return;
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* @param {string} value
|
|
78
|
+
*/
|
|
79
|
+
ct.String = (value) => {
|
|
80
|
+
if (!value) return undefined;
|
|
81
|
+
if (typeof value !== "string") return;
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* @param {boolean} value
|
|
86
|
+
*/
|
|
87
|
+
ct.Boolean = (value) => {
|
|
88
|
+
if (value === null) return undefined;
|
|
89
|
+
if (typeof value !== "boolean") return;
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* @param {object} value
|
|
94
|
+
*/
|
|
95
|
+
ct.Object = (value) => {
|
|
96
|
+
if (!value) return undefined;
|
|
97
|
+
if (typeof value !== "object") return;
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @param {function} value
|
|
102
|
+
*/
|
|
103
|
+
ct.Function = (value) => {
|
|
104
|
+
if (!value) return undefined;
|
|
105
|
+
if (typeof value !== "function") return;
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* @param {symbol} value
|
|
110
|
+
*/
|
|
111
|
+
ct.Symbol = (value) => {
|
|
112
|
+
if (!value) return undefined;
|
|
113
|
+
if (typeof value !== "symbol") return;
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* @param {URLPattern | "none"} value
|
|
118
|
+
*/
|
|
119
|
+
ct.Url = (value) => {
|
|
120
|
+
if (!value) return undefined;
|
|
121
|
+
if (!value.startsWith("http://") || !value.startsWith("https://")) return;
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
*
|
|
126
|
+
* @param {"home" | "search" | "menu" | "settings" | "favorite" | "account_circle" | "shopping_cart" | "notifications" | "info" | "help" | "exit_to_app" | "check_circle" | "close" | "edit" | "delete" | "add" | "arrow_back" | "arrow_forward" | "play_arrow" | "pause" | "stop" | "camera_alt" | "photo" | "alarm" | "event" | "attach_file" | "print" | "share" | "cloud" | "cloud_upload" | "cloud_download" | "lock" | "lock_open" | "visibility" | "visibility_off" | "phone" | "email" | "map" | "place" | "directions" | "train" | "directions_car" | "directions_bike" | "school" | "work" | "lightbulb" | "battery_full" | "battery_std" | "wifi" | "bluetooth"} value
|
|
127
|
+
* @returns
|
|
128
|
+
*/
|
|
129
|
+
ct.Icon = (value) => {
|
|
130
|
+
if (!value) return "help";
|
|
131
|
+
if (!iconsArray.includes(value)) return "help";
|
|
132
|
+
return value;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export default ct;
|