flet-box 0.0.0-stage โ 1.0.2
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/LICENSE +21 -0
- package/README.md +190 -2
- package/bin/cli.js +394 -0
- package/bin/commands/buildAndroid.js +200 -0
- package/bin/commands/buildIOS.js +237 -0
- package/bin/commands/create.js +406 -0
- package/bin/commands/createBundle.js +375 -0
- package/bin/commands/createComponent.js +115 -0
- package/bin/commands/createScreen.js +161 -0
- package/bin/commands/killServer.js +107 -0
- package/bin/commands/package.js +131 -0
- package/bin/commands/release.js +189 -0
- package/bin/commands/runBundle.js +62 -0
- package/bin/commands/runCloudflare.js +89 -0
- package/bin/commands/runNative.js +109 -0
- package/bin/commands/runServer.js +390 -0
- package/bin/ota/loader.js +361 -0
- package/bin/utils/bundleConfig.js +178 -0
- package/bin/utils/capacitor.js +137 -0
- package/bin/utils/colors.js +215 -0
- package/bin/utils/helpers.js +80 -0
- package/bin/utils/spinner.js +96 -0
- package/bin/utils/templates.js +1824 -0
- package/bin/utils/version.js +108 -0
- package/package.json +58 -4
- package/src/animations/AnimatedBox.js +607 -0
- package/src/animations/AnimatedText.js +105 -0
- package/src/animations/MatrixRain.js +220 -0
- package/src/animations/ParallaxBox.js +369 -0
- package/src/animations/animate.js +332 -0
- package/src/animations/index.js +25 -0
- package/src/app.js +41 -0
- package/src/assets/icon-1024-maskable.png +0 -0
- package/src/assets/icon-192-maskable.png +0 -0
- package/src/assets/icon-192.png +0 -0
- package/src/assets/icon-512-maskable.png +0 -0
- package/src/assets/icon-512.png +0 -0
- package/src/assets/logo.png +0 -0
- package/src/core/App.js +44 -0
- package/src/core/hmr-client.js +142 -0
- package/src/core/index.js +34 -0
- package/src/core/pwa.js +100 -0
- package/src/core/runApp.js +430 -0
- package/src/create-index.sh +237 -0
- package/src/fonts/MaterialIcons-Regular.woff2 +0 -0
- package/src/fonts/icons.css +23 -0
- package/src/index.d.ts +1930 -0
- package/src/index.js +288 -0
- package/src/navigations/AdaptiveScaffold.js +149 -0
- package/src/navigations/AppBar.js +331 -0
- package/src/navigations/BottomNavigation.js +298 -0
- package/src/navigations/CollapsibleSideBar.js +139 -0
- package/src/navigations/Drawer.js +333 -0
- package/src/navigations/DrawerItem.js +260 -0
- package/src/navigations/Router.js +475 -0
- package/src/navigations/Scaffold.js +537 -0
- package/src/navigations/Tabs.js +384 -0
- package/src/navigations/index.js +57 -0
- package/src/services/RamStore.js +213 -0
- package/src/services/Session.js +310 -0
- package/src/services/Storage.js +309 -0
- package/src/services/http.js +350 -0
- package/src/services/index.js +57 -0
- package/src/tools/animation.js +42 -0
- package/src/tools/array.js +95 -0
- package/src/tools/border.js +28 -0
- package/src/tools/clipboard.js +104 -0
- package/src/tools/color.js +329 -0
- package/src/tools/createList.js +215 -0
- package/src/tools/delay.js +55 -0
- package/src/tools/device.js +138 -0
- package/src/tools/dict.js +297 -0
- package/src/tools/dimensions.js +118 -0
- package/src/tools/filter.js +41 -0
- package/src/tools/flex.js +26 -0
- package/src/tools/gradient.js +34 -0
- package/src/tools/grid.js +57 -0
- package/src/tools/index.js +38 -0
- package/src/tools/mapList.js +107 -0
- package/src/tools/margin.js +93 -0
- package/src/tools/memo.js +60 -0
- package/src/tools/os.js +104 -0
- package/src/tools/padding.js +93 -0
- package/src/tools/print.js +69 -0
- package/src/tools/random.js +299 -0
- package/src/tools/ref.js +70 -0
- package/src/tools/rgba.js +4 -0
- package/src/tools/shadow.js +23 -0
- package/src/tools/string.js +85 -0
- package/src/tools/time.js +674 -0
- package/src/tools/transform.js +68 -0
- package/src/tools/transition.js +48 -0
- package/src/tools/useState.js +268 -0
- package/src/tools/uuid.js +42 -0
- package/src/utils/TextInputValidator.js +256 -0
- package/src/utils/composeUpdate.js +65 -0
- package/src/utils/getWidgetProps.js +35 -0
- package/src/utils/index.js +76 -0
- package/src/utils/markdownParser.js +368 -0
- package/src/utils/mediaTime.js +79 -0
- package/src/utils/navigation.js +263 -0
- package/src/utils/scriptInjector.js +73 -0
- package/src/utils/stackPosition.js +31 -0
- package/src/utils/stopWebRefresh.js +77 -0
- package/src/utils/styleInjector.js +38 -0
- package/src/utils/syntaxHighlight.js +339 -0
- package/src/utils/themes.js +347 -0
- package/src/utils/units.js +87 -0
- package/src/utils/visualEffects.js +169 -0
- package/src/widget-factory/addChildren.js +114 -0
- package/src/widget-factory/assignProps.js +256 -0
- package/src/widget-factory/createWidget.js +28 -0
- package/src/widget-factory/effects.js +132 -0
- package/src/widget-factory/index.js +7 -0
- package/src/widget-factory/lifecycle.js +210 -0
- package/src/widget-factory/makeParentable.js +89 -0
- package/src/widget-factory/pixTool.js +40 -0
- package/src/widget-factory/processProps.js +122 -0
- package/src/widget-factory/reactivity.js +98 -0
- package/src/widget-factory/remTool.js +34 -0
- package/src/widget-factory/stackPosition.js +87 -0
- package/src/widget-factory/stringTool.js +26 -0
- package/src/widget-factory/tools.js +249 -0
- package/src/widget-factory/translateProps.js +1049 -0
- package/src/widget-factory/warnings.js +284 -0
- package/src/widget-factory/widgetFactory.js +200 -0
- package/src/widgets/Accordion.js +562 -0
- package/src/widgets/AdMob.js +315 -0
- package/src/widgets/AdSense.js +268 -0
- package/src/widgets/AlertDialog.js +162 -0
- package/src/widgets/Audio.js +311 -0
- package/src/widgets/Avatar.js +210 -0
- package/src/widgets/Badge.js +189 -0
- package/src/widgets/BottomSheet.js +287 -0
- package/src/widgets/Button.js +247 -0
- package/src/widgets/Card.js +33 -0
- package/src/widgets/Carousel.js +301 -0
- package/src/widgets/Chart.js +632 -0
- package/src/widgets/Checkbox.js +106 -0
- package/src/widgets/Chip.js +153 -0
- package/src/widgets/CircularBar.js +352 -0
- package/src/widgets/CircularChart.js +549 -0
- package/src/widgets/CodeViewer.js +236 -0
- package/src/widgets/Column.js +29 -0
- package/src/widgets/Container.js +31 -0
- package/src/widgets/DataTable.js +257 -0
- package/src/widgets/Divider.js +93 -0
- package/src/widgets/DraggBox.js +115 -0
- package/src/widgets/Dropdown.js +505 -0
- package/src/widgets/DroppBox.js +180 -0
- package/src/widgets/FloatingActionButton.js +91 -0
- package/src/widgets/GridView.js +20 -0
- package/src/widgets/Icon.js +33 -0
- package/src/widgets/Image.js +15 -0
- package/src/widgets/Input.js +565 -0
- package/src/widgets/Inspector.js +254 -0
- package/src/widgets/InstallButton.js +110 -0
- package/src/widgets/ListTile.js +224 -0
- package/src/widgets/ListView.js +503 -0
- package/src/widgets/Markdown.js +1236 -0
- package/src/widgets/Modal.js +496 -0
- package/src/widgets/Pagination.js +195 -0
- package/src/widgets/ProgressBar.js +178 -0
- package/src/widgets/QRCode.js +467 -0
- package/src/widgets/Radio.js +132 -0
- package/src/widgets/Rating.js +261 -0
- package/src/widgets/Row.js +29 -0
- package/src/widgets/Skeleton.js +243 -0
- package/src/widgets/Slider.js +527 -0
- package/src/widgets/SnackBar.js +227 -0
- package/src/widgets/Stack.js +29 -0
- package/src/widgets/Stepper.js +296 -0
- package/src/widgets/Switch.js +102 -0
- package/src/widgets/Text.js +98 -0
- package/src/widgets/Tooltip.js +267 -0
- package/src/widgets/TreeView.js +370 -0
- package/src/widgets/Video.js +92 -0
- package/src/widgets/index.js +52 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// core/reactivity.js
|
|
2
|
+
import { REACTIVE_PROPS } from "./translateProps.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tags where `width` and `height` are native IDL attributes with their own
|
|
6
|
+
* semantics (intrinsic size, aspect-ratio, etc.). Overriding them with a custom
|
|
7
|
+
* `defineProperty` accessor would break that native behaviour, so these props
|
|
8
|
+
* are NOT shadowed on these tags.
|
|
9
|
+
*
|
|
10
|
+
* @type {Set<string>}
|
|
11
|
+
*/
|
|
12
|
+
const REPLACED_ELEMENT_TAGS = new Set([
|
|
13
|
+
"img",
|
|
14
|
+
"canvas",
|
|
15
|
+
"video",
|
|
16
|
+
"iframe",
|
|
17
|
+
"embed",
|
|
18
|
+
"object",
|
|
19
|
+
"source",
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Props that must NEVER be shadowed with a custom accessor because the browser
|
|
24
|
+
* maintains live, user-controlled state for them. For example, shadowing `value`
|
|
25
|
+
* on an `<input>` would disconnect `widget.value` from what the user is actually
|
|
26
|
+
* typing.
|
|
27
|
+
*
|
|
28
|
+
* @type {Set<string>}
|
|
29
|
+
*/
|
|
30
|
+
const NEVER_SHADOW = new Set(["value"]);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Installs reactive property accessors on a widget for every prop in
|
|
34
|
+
* `REACTIVE_PROPS`, excluding those guarded by `NEVER_SHADOW` and those that
|
|
35
|
+
* conflict with native IDL attributes on replaced elements.
|
|
36
|
+
*
|
|
37
|
+
* Each accessor follows this contract:
|
|
38
|
+
* - **getter** โ returns the prop's current value from `_originalProps`.
|
|
39
|
+
* - **setter** โ writes the new value to `_originalProps` and calls `updateFn`
|
|
40
|
+
* with a partial change object `{ [prop]: newValue }` only when the value
|
|
41
|
+
* actually changed (strict equality check prevents redundant updates).
|
|
42
|
+
*
|
|
43
|
+
* Additionally, for `<input>`, `<textarea>`, and `<select>` elements, syncs the
|
|
44
|
+
* DOM's own `value` back into `_originalProps` on every `input` and `change`
|
|
45
|
+
* event so that the stored props always reflect the live field content.
|
|
46
|
+
*
|
|
47
|
+
* @param {HTMLElement} widget - The widget to make reactive.
|
|
48
|
+
* @param {function(Object): void} updateFn - Callback invoked with the changed
|
|
49
|
+
* partial props whenever a reactive prop is set. Typically calls
|
|
50
|
+
* `widget.update(changedProps)`.
|
|
51
|
+
* @returns {HTMLElement} The same widget (for chaining).
|
|
52
|
+
*/
|
|
53
|
+
export const makeReactive = (widget, updateFn) => {
|
|
54
|
+
const tag = widget.tagName ? widget.tagName.toLowerCase() : "";
|
|
55
|
+
|
|
56
|
+
REACTIVE_PROPS.forEach((prop) => {
|
|
57
|
+
if (NEVER_SHADOW.has(prop)) return;
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
(prop === "width" || prop === "height") &&
|
|
61
|
+
REPLACED_ELEMENT_TAGS.has(tag)
|
|
62
|
+
) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
Object.defineProperty(widget, prop, {
|
|
67
|
+
get() {
|
|
68
|
+
return widget._originalProps ? widget._originalProps[prop] : undefined;
|
|
69
|
+
},
|
|
70
|
+
set(newValue) {
|
|
71
|
+
if (!widget._originalProps) return;
|
|
72
|
+
const current = widget._originalProps[prop];
|
|
73
|
+
if (current === newValue) return;
|
|
74
|
+
|
|
75
|
+
widget._originalProps[prop] = newValue;
|
|
76
|
+
updateFn({ [prop]: newValue });
|
|
77
|
+
},
|
|
78
|
+
enumerable: true,
|
|
79
|
+
configurable: true,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// For form elements, keep _originalProps in sync with the live DOM value so
|
|
84
|
+
// that getProps() always returns what the user has typed.
|
|
85
|
+
if (tag === "input" || tag === "textarea" || tag === "select") {
|
|
86
|
+
const syncValueFromDOM = () => {
|
|
87
|
+
if (widget._originalProps) {
|
|
88
|
+
widget._originalProps.value = widget.value;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
widget.addEventListener("input", syncValueFromDOM);
|
|
92
|
+
widget.addEventListener("change", syncValueFromDOM);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return widget;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default { makeReactive, REACTIVE_PROPS };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REM TOOL - Only converts numbers to REM
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Converts a number to REM
|
|
7
|
+
* @param {number} value - Number to convert
|
|
8
|
+
* @param {number} baseFontSize - Base root font size (default: 16)
|
|
9
|
+
* @returns {string} - Value in REM
|
|
10
|
+
*/
|
|
11
|
+
export const toREM = (value, baseFontSize = 16) => {
|
|
12
|
+
if (typeof value !== "number") return value;
|
|
13
|
+
return `${value / baseFontSize}rem`;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Applies REM to a styles object
|
|
18
|
+
* @param {Object} styles - Styles with numbers
|
|
19
|
+
* @param {number} baseFontSize - Base root font size (default: 16)
|
|
20
|
+
* @returns {Object} - Styles with REM
|
|
21
|
+
*/
|
|
22
|
+
export const applyREM = (styles, baseFontSize = 16) => {
|
|
23
|
+
const result = {};
|
|
24
|
+
|
|
25
|
+
for (const [key, value] of Object.entries(styles)) {
|
|
26
|
+
if (typeof value === "number") {
|
|
27
|
+
result[key] = toREM(value, baseFontSize);
|
|
28
|
+
} else {
|
|
29
|
+
result[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// core/stackPosition.js
|
|
2
|
+
import { toREM } from "./remTool.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Applies positioning for Stack layout
|
|
6
|
+
* @param {HTMLElement} widget - The widget to position
|
|
7
|
+
* @param {Object} props - Widget props
|
|
8
|
+
* @returns {HTMLElement} The widget with position applied
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* stackPosition(element, { position: 'stack', top: 10, left: 20 })
|
|
12
|
+
* // โ element.style.position = 'absolute'
|
|
13
|
+
* // โ element.style.top = '0.625rem'
|
|
14
|
+
* // โ element.style.left = '1.25rem'
|
|
15
|
+
*/
|
|
16
|
+
export const stackPosition = (widget, props) => {
|
|
17
|
+
// Numeric offsets follow the framework-wide rule: numbers are pixels on a
|
|
18
|
+
// 16px base, emitted as rem so they scale with the root font size.
|
|
19
|
+
const offset = (value) => (typeof value === "number" ? toREM(value) : value);
|
|
20
|
+
|
|
21
|
+
// Only apply if position is 'stack'
|
|
22
|
+
if (props.position !== "stack") {
|
|
23
|
+
return widget;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Absolute positioning
|
|
27
|
+
widget.style.position = "absolute";
|
|
28
|
+
|
|
29
|
+
// Process each position prop
|
|
30
|
+
for (const [key, value] of Object.entries(props)) {
|
|
31
|
+
if (key === "position") continue;
|
|
32
|
+
|
|
33
|
+
switch (key) {
|
|
34
|
+
case "top":
|
|
35
|
+
widget.style.top = offset(value);
|
|
36
|
+
break;
|
|
37
|
+
case "right":
|
|
38
|
+
widget.style.right = offset(value);
|
|
39
|
+
break;
|
|
40
|
+
case "bottom":
|
|
41
|
+
widget.style.bottom = offset(value);
|
|
42
|
+
break;
|
|
43
|
+
case "left":
|
|
44
|
+
widget.style.left = offset(value);
|
|
45
|
+
break;
|
|
46
|
+
case "start":
|
|
47
|
+
widget.style.left = offset(value);
|
|
48
|
+
break;
|
|
49
|
+
case "end":
|
|
50
|
+
widget.style.right = offset(value);
|
|
51
|
+
break;
|
|
52
|
+
case "centerX":
|
|
53
|
+
widget.style.left = "50%";
|
|
54
|
+
widget.style.transform = "translateX(-50%)";
|
|
55
|
+
break;
|
|
56
|
+
case "centerY":
|
|
57
|
+
widget.style.top = "50%";
|
|
58
|
+
widget.style.transform = "translateY(-50%)";
|
|
59
|
+
break;
|
|
60
|
+
case "center":
|
|
61
|
+
widget.style.top = "50%";
|
|
62
|
+
widget.style.left = "50%";
|
|
63
|
+
widget.style.transform = "translate(-50%, -50%)";
|
|
64
|
+
break;
|
|
65
|
+
case "fullWidth":
|
|
66
|
+
widget.style.width = "100%";
|
|
67
|
+
widget.style.left = "0";
|
|
68
|
+
widget.style.right = "0";
|
|
69
|
+
break;
|
|
70
|
+
case "fullHeight":
|
|
71
|
+
widget.style.height = "100%";
|
|
72
|
+
widget.style.top = "0";
|
|
73
|
+
widget.style.bottom = "0";
|
|
74
|
+
break;
|
|
75
|
+
case "full":
|
|
76
|
+
widget.style.width = "100%";
|
|
77
|
+
widget.style.height = "100%";
|
|
78
|
+
widget.style.top = "0";
|
|
79
|
+
widget.style.left = "0";
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return widget;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default stackPosition;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* STRING TOOL - Only keeps props that are strings
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Filters and keeps only string values
|
|
7
|
+
* @param {Object} styles - Styles object
|
|
8
|
+
* @returns {Object} - Only string props
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* keepStrings({ padding: 16, color: 'red', display: 'flex', zIndex: 10 })
|
|
12
|
+
* // โ { color: 'red', display: 'flex' }
|
|
13
|
+
*/
|
|
14
|
+
export const keepStrings = (styles) => {
|
|
15
|
+
const result = {};
|
|
16
|
+
|
|
17
|
+
for (const [key, value] of Object.entries(styles)) {
|
|
18
|
+
if (typeof value === "string") {
|
|
19
|
+
result[key] = value;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default keepStrings;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// ๐ READ: Get styles
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Reads one or all inline styles from a DOM element.
|
|
7
|
+
*
|
|
8
|
+
* @param {HTMLElement|null} el - The target element.
|
|
9
|
+
* @param {string} [prop] - CSS property name. When provided, returns only that
|
|
10
|
+
* property's value (or `null` when absent). When omitted, returns an object
|
|
11
|
+
* containing every non-empty inline style.
|
|
12
|
+
* @returns {string|Object|null} The property value, a styles object, or `null`
|
|
13
|
+
* when `el` is falsy or the property is not set.
|
|
14
|
+
*/
|
|
15
|
+
export function getStyles(el, prop) {
|
|
16
|
+
if (!el) return null;
|
|
17
|
+
if (prop) return el.style[prop] || null;
|
|
18
|
+
|
|
19
|
+
const styles = {};
|
|
20
|
+
for (let i = 0; i < el.style.length; i++) {
|
|
21
|
+
const p = el.style[i];
|
|
22
|
+
const v = el.style[p];
|
|
23
|
+
if (v !== "") styles[p] = v;
|
|
24
|
+
}
|
|
25
|
+
return styles;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ============================================================
|
|
29
|
+
// โ CREATE / UPDATE: Assign styles
|
|
30
|
+
// ============================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Converts a raw prop value to a CSS-ready string or number.
|
|
34
|
+
*
|
|
35
|
+
* Conversion rules:
|
|
36
|
+
* - **Array** โ space-separated string (e.g. `[12, 24]` โ `"12px 24px"`).
|
|
37
|
+
* - **Number** on a unitless prop (flex, zIndex, opacity, etc.) โ returned
|
|
38
|
+
* as-is without a suffix.
|
|
39
|
+
* - **Number** on any other prop โ suffixed with `"px"`.
|
|
40
|
+
* - **String** โ returned unchanged.
|
|
41
|
+
* - `undefined` / `null` โ returned as `null` (caller should skip assignment).
|
|
42
|
+
*
|
|
43
|
+
* @param {string} key - The CSS property name (camelCase).
|
|
44
|
+
* @param {*} value - The raw value to convert.
|
|
45
|
+
* @returns {string|number|null} The CSS-ready value, or `null` to skip.
|
|
46
|
+
*/
|
|
47
|
+
const toCSSValue = (key, value) => {
|
|
48
|
+
if (value === undefined || value === null) return null;
|
|
49
|
+
|
|
50
|
+
// Array โ "12px 24px"
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
return value.map((v) => (typeof v === "number" ? `${v}px` : v)).join(" ");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Number โ apply unit or no unit
|
|
56
|
+
if (typeof value === "number") {
|
|
57
|
+
// Props that must NOT receive a unit suffix
|
|
58
|
+
const noUnitProps = new Set([
|
|
59
|
+
"flex",
|
|
60
|
+
"flexGrow",
|
|
61
|
+
"flexShrink",
|
|
62
|
+
"order",
|
|
63
|
+
"zIndex",
|
|
64
|
+
"opacity",
|
|
65
|
+
"fontWeight",
|
|
66
|
+
"lineHeight",
|
|
67
|
+
"scale",
|
|
68
|
+
"rotate",
|
|
69
|
+
"rotateX",
|
|
70
|
+
"rotateY",
|
|
71
|
+
"rotateZ",
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
if (noUnitProps.has(key)) {
|
|
75
|
+
return value; // No unit
|
|
76
|
+
}
|
|
77
|
+
return `${value}px`; // Add px
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// String โ keep as is
|
|
81
|
+
return value;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Applies one or more styles to a DOM element.
|
|
86
|
+
*
|
|
87
|
+
* Supports two call signatures:
|
|
88
|
+
* 1. `setStyles(el, propName, value)` โ sets a single CSS property.
|
|
89
|
+
* 2. `setStyles(el, stylesObject)` โ applies every key/value pair in the object.
|
|
90
|
+
*
|
|
91
|
+
* Values are converted via `toCSSValue` before assignment. Invalid CSS
|
|
92
|
+
* assignments (e.g. read-only properties) are silently ignored.
|
|
93
|
+
*
|
|
94
|
+
* @param {HTMLElement} el - The target element.
|
|
95
|
+
* @param {string|Object} prop - CSS property name (camelCase) or an object of
|
|
96
|
+
* propertyโvalue pairs.
|
|
97
|
+
* @param {*} [value] - The value to assign. Required when `prop` is a string.
|
|
98
|
+
* @returns {HTMLElement} The element (for chaining).
|
|
99
|
+
*/
|
|
100
|
+
export function setStyles(el, prop, value) {
|
|
101
|
+
// Validateste element
|
|
102
|
+
if (!el || !el.style) return el;
|
|
103
|
+
|
|
104
|
+
// Case 1: string (prop + value)
|
|
105
|
+
if (typeof prop === "string") {
|
|
106
|
+
const cssValue = toCSSValue(prop, value);
|
|
107
|
+
if (cssValue !== null) {
|
|
108
|
+
try {
|
|
109
|
+
el.style[prop] = cssValue;
|
|
110
|
+
} catch (e) {
|
|
111
|
+
// Silently ignore errors
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return el;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Case 2: styles object
|
|
118
|
+
if (typeof prop === "object" && prop !== null) {
|
|
119
|
+
for (const [key, val] of Object.entries(prop)) {
|
|
120
|
+
const cssValue = toCSSValue(key, val);
|
|
121
|
+
if (cssValue !== null) {
|
|
122
|
+
try {
|
|
123
|
+
el.style[key] = cssValue;
|
|
124
|
+
} catch (e) {
|
|
125
|
+
// Silently ignore errors
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return el;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ============================================================
|
|
135
|
+
// ๐ TOGGLE: Toggle styles
|
|
136
|
+
// ============================================================
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Toggles a CSS property between two values.
|
|
140
|
+
*
|
|
141
|
+
* If the property currently equals `val1` it is set to `val2`, and vice versa.
|
|
142
|
+
* Useful for toggling visibility, themes, or active states without external
|
|
143
|
+
* boolean tracking.
|
|
144
|
+
*
|
|
145
|
+
* @param {HTMLElement} el - The target element.
|
|
146
|
+
* @param {string} prop - CSS property name (camelCase).
|
|
147
|
+
* @param {*} val1 - First value (the one to switch away from when current).
|
|
148
|
+
* @param {*} val2 - Second value (the one to switch away from when current).
|
|
149
|
+
* @returns {HTMLElement} The element (for chaining).
|
|
150
|
+
*/
|
|
151
|
+
export function updateStyle(el, prop, val1, val2) {
|
|
152
|
+
if (!el || !prop) return el;
|
|
153
|
+
|
|
154
|
+
const current = el.style[prop] || "";
|
|
155
|
+
const newValue = current === val1 ? val2 : val1;
|
|
156
|
+
const cssValue = toCSSValue(prop, newValue);
|
|
157
|
+
|
|
158
|
+
if (cssValue !== null) {
|
|
159
|
+
try {
|
|
160
|
+
el.style[prop] = cssValue;
|
|
161
|
+
} catch (e) {
|
|
162
|
+
// Silently ignore errors
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return el;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ============================================================
|
|
170
|
+
// ๐๏ธ DELETE: Remove styles
|
|
171
|
+
// ============================================================
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Removes one or more inline styles from a DOM element by setting them to an
|
|
175
|
+
* empty string (which causes the browser to fall back to inherited / default
|
|
176
|
+
* values).
|
|
177
|
+
*
|
|
178
|
+
* - `string` โ removes that single property.
|
|
179
|
+
* - `Array<string>` โ removes every listed property.
|
|
180
|
+
* - `undefined` โ removes ALL currently set inline styles.
|
|
181
|
+
*
|
|
182
|
+
* @param {HTMLElement} el - The target element.
|
|
183
|
+
* @param {string|string[]|undefined} [prop] - Property or properties to remove.
|
|
184
|
+
* Omit to remove all inline styles.
|
|
185
|
+
* @returns {HTMLElement} The element (for chaining).
|
|
186
|
+
*/
|
|
187
|
+
export function removeStyles(el, prop) {
|
|
188
|
+
if (!el) return el;
|
|
189
|
+
|
|
190
|
+
if (typeof prop === "string") {
|
|
191
|
+
try {
|
|
192
|
+
el.style[prop] = "";
|
|
193
|
+
} catch (e) {}
|
|
194
|
+
} else if (Array.isArray(prop)) {
|
|
195
|
+
prop.forEach((p) => {
|
|
196
|
+
try {
|
|
197
|
+
el.style[p] = "";
|
|
198
|
+
} catch (e) {}
|
|
199
|
+
});
|
|
200
|
+
} else if (prop === undefined) {
|
|
201
|
+
const styles = getStyles(el);
|
|
202
|
+
Object.keys(styles).forEach((p) => {
|
|
203
|
+
try {
|
|
204
|
+
el.style[p] = "";
|
|
205
|
+
} catch (e) {}
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return el;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ============================================================
|
|
212
|
+
// ๐ UTILITY: Check styles
|
|
213
|
+
// ============================================================
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Checks whether a specific inline style is set on an element.
|
|
217
|
+
*
|
|
218
|
+
* @param {HTMLElement|null} el - The target element.
|
|
219
|
+
* @param {string} prop - CSS property name (camelCase).
|
|
220
|
+
* @returns {boolean} `true` if the property has a non-empty inline value.
|
|
221
|
+
*/
|
|
222
|
+
export function hasStyle(el, prop) {
|
|
223
|
+
if (!el || !prop) return false;
|
|
224
|
+
return el.style[prop] !== "";
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Logs all inline styles of an element to the console in a readable format.
|
|
229
|
+
* Useful for debugging style issues during development.
|
|
230
|
+
*
|
|
231
|
+
* @param {HTMLElement|null} el - The target element.
|
|
232
|
+
* @param {string} [label="Styles"] - Label prefix shown in the console output.
|
|
233
|
+
* @returns {Object|null} The styles object (same as `getStyles(el)`), or `null`
|
|
234
|
+
* when `el` is falsy.
|
|
235
|
+
*/
|
|
236
|
+
export function logStyles(el, label = "Styles") {
|
|
237
|
+
if (!el) {
|
|
238
|
+
console.warn("โ ๏ธ Invalid element");
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
const styles = getStyles(el);
|
|
242
|
+
console.log(`๐ ${label}:`);
|
|
243
|
+
if (Object.keys(styles).length === 0) {
|
|
244
|
+
console.log(" (No inline styles)");
|
|
245
|
+
} else {
|
|
246
|
+
Object.entries(styles).forEach(([p, v]) => console.log(` ${p}: ${v}`));
|
|
247
|
+
}
|
|
248
|
+
return styles;
|
|
249
|
+
}
|