jswidthbreakpoints 1.0.0 → 1.0.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/.vscode/settings.json +1 -1
- package/README.md +1 -1
- package/demo/index.html +26 -34
- package/demo/style.css +60 -33
- package/dist/JsWidthBreakpoints.js +243 -0
- package/dist/JsWidthBreakpoints.min.js +3 -3
- package/gulpfile.js +16 -10
- package/images/screen-2.png +0 -0
- package/package.json +3 -2
- package/src/JsWidthBreakpoints.js +100 -84
package/.vscode/settings.json
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# JsWidthBreakpoints
|
|
2
2
|
|
|
3
|
-

|
|
3
|
+

|
|
4
4
|
|
|
5
5
|

|
|
6
6
|

|
package/demo/index.html
CHANGED
|
@@ -5,24 +5,15 @@
|
|
|
5
5
|
<meta charset="UTF-8">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>JsWidthBreakpoints - Demo</title>
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
|
|
8
11
|
<link rel="stylesheet" href="style.css">
|
|
9
12
|
<style>
|
|
10
|
-
|
|
11
|
-
.width-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
.width-b400a600 .area {
|
|
16
|
-
background-color: cornflowerblue;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.width-b600a800 .area {
|
|
20
|
-
background-color: lightseagreen;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.width-gt800 .area {
|
|
24
|
-
background-color: darkslateblue;
|
|
25
|
-
}
|
|
13
|
+
.width-lt400 .area { --zone-color: #f87171; }
|
|
14
|
+
.width-b400a600 .area { --zone-color: #60a5fa; }
|
|
15
|
+
.width-b600a800 .area { --zone-color: #34d399; }
|
|
16
|
+
.width-gt800 .area { --zone-color: #a78bfa; }
|
|
26
17
|
</style>
|
|
27
18
|
</head>
|
|
28
19
|
|
|
@@ -30,16 +21,24 @@
|
|
|
30
21
|
<div class="container">
|
|
31
22
|
<div class="area">
|
|
32
23
|
<h1>JsWidthBreakpoints</h1>
|
|
33
|
-
<p>Resize the window to see the CSS classes being applied.</p>
|
|
24
|
+
<p class="subtitle">Resize the window to see the CSS classes being applied.</p>
|
|
34
25
|
<div class="card">
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
<div class="card-row">
|
|
27
|
+
<span class="card-label">Breakpoints</span>
|
|
28
|
+
<span class="card-value mono" id="widths">[400, 600, 800]</span>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="card-row">
|
|
31
|
+
<span class="card-label">Current width</span>
|
|
32
|
+
<span class="card-value mono"><span id="width">—</span>px</span>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="card-row">
|
|
35
|
+
<span class="card-label">Active class</span>
|
|
36
|
+
<span class="card-value mono accent" id="active-class">—</span>
|
|
37
|
+
</div>
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
|
-
<!-- JsWidthBreakpoints Library -->
|
|
43
42
|
<script src="../dist/JsWidthBreakpoints.js"></script>
|
|
44
43
|
<script>
|
|
45
44
|
JsWidthBreakpoints.init({
|
|
@@ -47,9 +46,9 @@
|
|
|
47
46
|
applyClasses: true,
|
|
48
47
|
classPrefix: 'width-',
|
|
49
48
|
rule: {
|
|
50
|
-
show: true,
|
|
51
|
-
opacity: 1,
|
|
52
|
-
color: 'red',
|
|
49
|
+
show: true,
|
|
50
|
+
opacity: 1,
|
|
51
|
+
color: 'red',
|
|
53
52
|
},
|
|
54
53
|
onBreakPoint: (event) => {
|
|
55
54
|
console.log('Breakpoint reached:', event);
|
|
@@ -57,18 +56,11 @@
|
|
|
57
56
|
});
|
|
58
57
|
|
|
59
58
|
const drawInfo = () => {
|
|
60
|
-
document.getElementById('
|
|
61
|
-
|
|
62
|
-
<br>
|
|
63
|
-
Current breakpoint: ${JsWidthBreakpoints.currentClass}</p>
|
|
64
|
-
`;
|
|
59
|
+
document.getElementById('width').textContent = window.innerWidth;
|
|
60
|
+
document.getElementById('active-class').textContent = '.' + JsWidthBreakpoints.currentClass;
|
|
65
61
|
};
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
window.addEventListener('resize', (event) => {
|
|
69
|
-
drawInfo();
|
|
70
|
-
});
|
|
71
|
-
|
|
63
|
+
window.addEventListener('resize', drawInfo);
|
|
72
64
|
drawInfo();
|
|
73
65
|
</script>
|
|
74
66
|
</body>
|
package/demo/style.css
CHANGED
|
@@ -1,59 +1,86 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--zone-color: #a78bfa;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
6
|
+
|
|
1
7
|
body {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
color: #fff;
|
|
8
|
+
font-family: 'Inter', sans-serif;
|
|
9
|
+
background-color: #18181b;
|
|
10
|
+
color: #e4e4e7;
|
|
6
11
|
display: flex;
|
|
7
12
|
justify-content: center;
|
|
8
|
-
height: 100vh;
|
|
9
|
-
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
padding: 6vh 1rem;
|
|
15
|
+
transition: background-color 0.5s ease;
|
|
10
16
|
}
|
|
11
17
|
|
|
12
18
|
.container {
|
|
13
19
|
width: 80vw;
|
|
14
|
-
max-width:
|
|
15
|
-
min-width:
|
|
16
|
-
margin-top: 5vh;
|
|
20
|
+
max-width: 520px;
|
|
21
|
+
min-width: 280px;
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
.area {
|
|
20
|
-
padding:
|
|
21
|
-
border-radius:
|
|
22
|
-
border: 1px solid #
|
|
25
|
+
padding: 2.5rem 2rem;
|
|
26
|
+
border-radius: 16px;
|
|
27
|
+
border: 1px solid var(--zone-color, #3f3f46);
|
|
28
|
+
background: color-mix(in srgb, var(--zone-color) 15%, #1c1c1f);
|
|
29
|
+
box-shadow: 0 0 40px -10px color-mix(in srgb, var(--zone-color) 30%, transparent);
|
|
30
|
+
transition: border-color 0.4s ease, box-shadow 0.4s ease, background 0.4s ease;
|
|
31
|
+
text-align: center;
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
h1 {
|
|
26
|
-
font-size: clamp(1.
|
|
27
|
-
|
|
35
|
+
font-size: clamp(1.4rem, 4vw, 2rem);
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
letter-spacing: -0.03em;
|
|
38
|
+
color: #fff;
|
|
39
|
+
margin-bottom: 0.5rem;
|
|
28
40
|
}
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
font-size:
|
|
42
|
+
.subtitle {
|
|
43
|
+
font-size: 0.875rem;
|
|
44
|
+
color: #71717a;
|
|
45
|
+
margin-bottom: 2rem;
|
|
32
46
|
}
|
|
33
47
|
|
|
34
|
-
|
|
35
|
-
|
|
48
|
+
.card {
|
|
49
|
+
background: #111113;
|
|
50
|
+
border: 1px solid #2d2d30;
|
|
51
|
+
border-radius: 10px;
|
|
52
|
+
overflow: hidden;
|
|
53
|
+
text-align: left;
|
|
36
54
|
}
|
|
37
55
|
|
|
38
|
-
.card {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
.card-row {
|
|
57
|
+
display: flex;
|
|
58
|
+
justify-content: space-between;
|
|
59
|
+
align-items: center;
|
|
60
|
+
padding: 0.75rem 1.1rem;
|
|
61
|
+
border-bottom: 1px solid #2d2d30;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.card-row:last-child {
|
|
65
|
+
border-bottom: none;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.card-label {
|
|
69
|
+
font-size: 0.8rem;
|
|
70
|
+
color: #71717a;
|
|
45
71
|
}
|
|
46
72
|
|
|
47
|
-
.card
|
|
48
|
-
|
|
73
|
+
.card-value {
|
|
74
|
+
font-size: 0.85rem;
|
|
75
|
+
color: #e4e4e7;
|
|
76
|
+
font-weight: 500;
|
|
49
77
|
}
|
|
50
78
|
|
|
51
|
-
|
|
52
|
-
font-
|
|
53
|
-
font-size: larger;
|
|
54
|
-
color: deeppink;
|
|
79
|
+
.mono {
|
|
80
|
+
font-family: 'JetBrains Mono', monospace;
|
|
55
81
|
}
|
|
56
82
|
|
|
57
|
-
.
|
|
58
|
-
|
|
83
|
+
.accent {
|
|
84
|
+
color: var(--zone-color);
|
|
85
|
+
transition: color 0.4s ease;
|
|
59
86
|
}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JsWidthBreakpoints - A lightweight, vanilla JavaScript library for handling responsive breakpoints with dynamic CSS classes and visual rules.
|
|
3
|
+
* Version: 1.0.1
|
|
4
|
+
* Repository: https://github.com/marceloxp/JsWidthBreakpoints
|
|
5
|
+
* License: MIT
|
|
6
|
+
* Author: Marcelo XP
|
|
7
|
+
* Build Date: 2026-03-15
|
|
8
|
+
*/
|
|
9
|
+
class JsWidthBreakpoints {
|
|
10
|
+
// Default settings
|
|
11
|
+
static defaults = {
|
|
12
|
+
widths: [], // Array of breakpoints in pixels (e.g., [400, 600, 800, 1200])
|
|
13
|
+
onBreakPoint: null, // Callback function when breakpoint changes
|
|
14
|
+
applyClasses: true, // Whether to apply CSS classes to <body>
|
|
15
|
+
classPrefix: 'width-', // Prefix for generated CSS classes
|
|
16
|
+
rule: {
|
|
17
|
+
show: false, // Whether to display the rule
|
|
18
|
+
opacity: 1, // Opacity of the rule
|
|
19
|
+
color: 'red', // Color of the rule
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Flag to prevent multiple initializations
|
|
24
|
+
static _isInitialized = false;
|
|
25
|
+
|
|
26
|
+
// Initialize the library
|
|
27
|
+
static init(options = {}) {
|
|
28
|
+
if (this._isInitialized) {
|
|
29
|
+
console.warn('JsWidthBreakpoints is already initialized. Ignoring subsequent init call.');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Deep merge only on rule object
|
|
34
|
+
const userOptions = options || {};
|
|
35
|
+
const mergedRule = { ...this.defaults.rule, ...(userOptions.rule || {}) };
|
|
36
|
+
|
|
37
|
+
this.options = {
|
|
38
|
+
...this.defaults,
|
|
39
|
+
...userOptions,
|
|
40
|
+
rule: mergedRule,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Sort breakpoints in descending order
|
|
44
|
+
this.breakpoints = [...(this.options.widths || [])]
|
|
45
|
+
.filter(v => Number.isInteger(v) && v > 0)
|
|
46
|
+
.sort((a, b) => b - a);
|
|
47
|
+
|
|
48
|
+
this.breakpoints_length = this.breakpoints.length;
|
|
49
|
+
|
|
50
|
+
// Key decision: no valid breakpoints → doesn't initialize anything
|
|
51
|
+
if (this.breakpoints_length === 0) {
|
|
52
|
+
console.warn('JsWidthBreakpoints: No valid breakpoints provided. Library will not be activated.');
|
|
53
|
+
this._isInitialized = true;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
this.smallestBreakpoint = this.breakpoints[this.breakpoints_length - 1];
|
|
58
|
+
this.biggestBreakpoint = this.breakpoints[0];
|
|
59
|
+
this.allBreakpointClasses = this.getAllBreakpointClasses();
|
|
60
|
+
|
|
61
|
+
// Check if the callback is a function
|
|
62
|
+
this.hasCallback = typeof this.options.onBreakPoint === 'function';
|
|
63
|
+
// Get the current window width
|
|
64
|
+
this.currentWidth = this.getWindowWidth();
|
|
65
|
+
// Store the current class name
|
|
66
|
+
this.currentClass = null;
|
|
67
|
+
|
|
68
|
+
// Set up the window resize listener
|
|
69
|
+
this.setupEventListeners();
|
|
70
|
+
|
|
71
|
+
// Check and apply breakpoints immediately
|
|
72
|
+
this.checkBreakpoints();
|
|
73
|
+
|
|
74
|
+
// Initialize the rule if enabled
|
|
75
|
+
if (this.options.rule.show) {
|
|
76
|
+
this.injectRuleStyles();
|
|
77
|
+
this.createRule();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this._isInitialized = true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Get all possible breakpoint class names
|
|
84
|
+
static getAllBreakpointClasses() {
|
|
85
|
+
if (this.breakpoints_length === 0) return [];
|
|
86
|
+
|
|
87
|
+
const result = [
|
|
88
|
+
`lt${this.smallestBreakpoint}`,
|
|
89
|
+
`gt${this.biggestBreakpoint}`,
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
for (let i = 1; i < this.breakpoints_length; i++) {
|
|
93
|
+
const lower = this.breakpoints[i];
|
|
94
|
+
const higher = this.breakpoints[i - 1];
|
|
95
|
+
result.push(`b${lower}a${higher}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Get the current window width
|
|
102
|
+
static getWindowWidth() {
|
|
103
|
+
return window.innerWidth;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Set up the window resize listener
|
|
107
|
+
static setupEventListeners() {
|
|
108
|
+
window.addEventListener('resize', () => this.checkBreakpoints());
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Main logic - simplified and callback always works
|
|
112
|
+
static checkBreakpoints() {
|
|
113
|
+
const newWidth = this.getWindowWidth();
|
|
114
|
+
this.currentWidth = newWidth;
|
|
115
|
+
|
|
116
|
+
const breakpoint = this.getCurrentBreakpoint();
|
|
117
|
+
|
|
118
|
+
if (breakpoint !== this.currentClass) {
|
|
119
|
+
const oldBreakpoint = this.currentClass || '';
|
|
120
|
+
this.currentClass = breakpoint;
|
|
121
|
+
|
|
122
|
+
// Execute the callback if defined
|
|
123
|
+
if (this.hasCallback) {
|
|
124
|
+
this.options.onBreakPoint({
|
|
125
|
+
oldBreakpoint,
|
|
126
|
+
currentWidth: newWidth,
|
|
127
|
+
currentBreakpoint: breakpoint,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Apply classes only if enabled
|
|
132
|
+
if (this.options.applyClasses) {
|
|
133
|
+
this.applyBreakpointClasses(breakpoint);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static getCurrentBreakpoint() {
|
|
139
|
+
if (this.breakpoints_length === 0) return null;
|
|
140
|
+
|
|
141
|
+
const w = this.currentWidth;
|
|
142
|
+
|
|
143
|
+
if (w <= this.smallestBreakpoint) {
|
|
144
|
+
return `lt${this.smallestBreakpoint}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (w >= this.biggestBreakpoint) {
|
|
148
|
+
return `gt${this.biggestBreakpoint}`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
for (let i = 1; i < this.breakpoints_length; i++) {
|
|
152
|
+
const higher = this.breakpoints[i - 1];
|
|
153
|
+
const lower = this.breakpoints[i];
|
|
154
|
+
|
|
155
|
+
if (w >= lower && w < higher) {
|
|
156
|
+
return `b${lower}a${higher}`;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
static applyBreakpointClasses(breakpoint) {
|
|
164
|
+
const body = document.body;
|
|
165
|
+
const prefix = this.options.classPrefix;
|
|
166
|
+
|
|
167
|
+
// Remove all possible classes first
|
|
168
|
+
this.allBreakpointClasses.forEach((cls) => {
|
|
169
|
+
body.classList.remove(`${prefix}${cls}`);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Add current one
|
|
173
|
+
if (breakpoint) {
|
|
174
|
+
body.classList.add(`${prefix}${breakpoint}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
static injectRuleStyles() {
|
|
179
|
+
const styleId = 'jsWidthBreakpointsRuleStyles';
|
|
180
|
+
if (document.getElementById(styleId)) return;
|
|
181
|
+
|
|
182
|
+
const styles = `
|
|
183
|
+
.JsWidthBreakpoints-rule {
|
|
184
|
+
position: fixed;
|
|
185
|
+
top: 0; left: 0;
|
|
186
|
+
width: 100%; height: 100%;
|
|
187
|
+
pointer-events: none;
|
|
188
|
+
z-index: 1000;
|
|
189
|
+
}
|
|
190
|
+
.JsWidthBreakpoints-rule-line {
|
|
191
|
+
position: absolute;
|
|
192
|
+
top: 0; height: 100%;
|
|
193
|
+
width: 1px;
|
|
194
|
+
background-color: ${this.options.rule.color};
|
|
195
|
+
opacity: ${this.options.rule.opacity};
|
|
196
|
+
}
|
|
197
|
+
.JsWidthBreakpoints-rule-label {
|
|
198
|
+
position: absolute;
|
|
199
|
+
top: 10px;
|
|
200
|
+
left: 5px;
|
|
201
|
+
background-color: dimgrey;
|
|
202
|
+
color: white;
|
|
203
|
+
padding: 4px 6px;
|
|
204
|
+
font-size: 12px;
|
|
205
|
+
border-radius: 3px;
|
|
206
|
+
font-family: monospace;
|
|
207
|
+
box-shadow: 1px 1px 1px 0px rgba(0,0,0,0.75);
|
|
208
|
+
opacity: ${this.options.rule.opacity};
|
|
209
|
+
}
|
|
210
|
+
`;
|
|
211
|
+
|
|
212
|
+
const style = document.createElement('style');
|
|
213
|
+
style.id = styleId;
|
|
214
|
+
style.textContent = styles;
|
|
215
|
+
document.head.appendChild(style);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static createRule() {
|
|
219
|
+
const ruleContainer = document.createElement('div');
|
|
220
|
+
ruleContainer.className = 'JsWidthBreakpoints-rule';
|
|
221
|
+
|
|
222
|
+
// Lines from largest to smallest (visual order)
|
|
223
|
+
this.breakpoints.forEach((width) => {
|
|
224
|
+
const line = document.createElement('div');
|
|
225
|
+
line.className = 'JsWidthBreakpoints-rule-line';
|
|
226
|
+
line.style.left = `${width}px`;
|
|
227
|
+
|
|
228
|
+
const label = document.createElement('div');
|
|
229
|
+
label.className = 'JsWidthBreakpoints-rule-label';
|
|
230
|
+
label.textContent = `${width}px`;
|
|
231
|
+
label.style.left = `${width + 5}px`;
|
|
232
|
+
|
|
233
|
+
ruleContainer.appendChild(line);
|
|
234
|
+
ruleContainer.appendChild(label);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// Add the rule container to the body
|
|
238
|
+
document.body.appendChild(ruleContainer);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Expose globally
|
|
243
|
+
window.JsWidthBreakpoints = JsWidthBreakpoints;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JsWidthBreakpoints - A lightweight, vanilla JavaScript library for handling responsive breakpoints with dynamic CSS classes and visual rules.
|
|
3
|
-
* Version: 1.0.
|
|
3
|
+
* Version: 1.0.1
|
|
4
4
|
* Repository: https://github.com/marceloxp/JsWidthBreakpoints
|
|
5
5
|
* License: MIT
|
|
6
6
|
* Author: Marcelo XP
|
|
7
|
-
* Build Date:
|
|
7
|
+
* Build Date: 2026-03-15
|
|
8
8
|
*/
|
|
9
|
-
class JsWidthBreakpoints{static defaults={widths:[],onBreakPoint:null,applyClasses:!0,classPrefix:"width-",rule:{show:!1,opacity:1,color:"red"}};static init(t={}){this.options={...this.defaults,...
|
|
9
|
+
class JsWidthBreakpoints{static defaults={widths:[],onBreakPoint:null,applyClasses:!0,classPrefix:"width-",rule:{show:!1,opacity:1,color:"red"}};static _isInitialized=!1;static init(t={}){if(this._isInitialized)return void console.warn("JsWidthBreakpoints is already initialized. Ignoring subsequent init call.");const i=t||{},s={...this.defaults.rule,...i.rule||{}};if(this.options={...this.defaults,...i,rule:s},this.breakpoints=[...this.options.widths||[]].filter((t=>Number.isInteger(t)&&t>0)).sort(((t,i)=>i-t)),this.breakpoints_length=this.breakpoints.length,0===this.breakpoints_length)return console.warn("JsWidthBreakpoints: No valid breakpoints provided. Library will not be activated."),void(this._isInitialized=!0);this.smallestBreakpoint=this.breakpoints[this.breakpoints_length-1],this.biggestBreakpoint=this.breakpoints[0],this.allBreakpointClasses=this.getAllBreakpointClasses(),this.hasCallback="function"==typeof this.options.onBreakPoint,this.currentWidth=this.getWindowWidth(),this.currentClass=null,this.setupEventListeners(),this.checkBreakpoints(),this.options.rule.show&&(this.injectRuleStyles(),this.createRule()),this._isInitialized=!0}static getAllBreakpointClasses(){if(0===this.breakpoints_length)return[];const t=[`lt${this.smallestBreakpoint}`,`gt${this.biggestBreakpoint}`];for(let i=1;i<this.breakpoints_length;i++){const s=this.breakpoints[i],e=this.breakpoints[i-1];t.push(`b${s}a${e}`)}return t}static getWindowWidth(){return window.innerWidth}static setupEventListeners(){window.addEventListener("resize",(()=>this.checkBreakpoints()))}static checkBreakpoints(){const t=this.getWindowWidth();this.currentWidth=t;const i=this.getCurrentBreakpoint();if(i!==this.currentClass){const s=this.currentClass||"";this.currentClass=i,this.hasCallback&&this.options.onBreakPoint({oldBreakpoint:s,currentWidth:t,currentBreakpoint:i}),this.options.applyClasses&&this.applyBreakpointClasses(i)}}static getCurrentBreakpoint(){if(0===this.breakpoints_length)return null;const t=this.currentWidth;if(t<=this.smallestBreakpoint)return`lt${this.smallestBreakpoint}`;if(t>=this.biggestBreakpoint)return`gt${this.biggestBreakpoint}`;for(let i=1;i<this.breakpoints_length;i++){const s=this.breakpoints[i-1],e=this.breakpoints[i];if(t>=e&&t<s)return`b${e}a${s}`}return null}static applyBreakpointClasses(t){const i=document.body,s=this.options.classPrefix;this.allBreakpointClasses.forEach((t=>{i.classList.remove(`${s}${t}`)})),t&&i.classList.add(`${s}${t}`)}static injectRuleStyles(){const t="jsWidthBreakpointsRuleStyles";if(document.getElementById(t))return;const i=`\n .JsWidthBreakpoints-rule {\n position: fixed;\n top: 0; left: 0;\n width: 100%; height: 100%;\n pointer-events: none;\n z-index: 1000;\n }\n .JsWidthBreakpoints-rule-line {\n position: absolute;\n top: 0; height: 100%;\n width: 1px;\n background-color: ${this.options.rule.color};\n opacity: ${this.options.rule.opacity};\n }\n .JsWidthBreakpoints-rule-label {\n position: absolute;\n top: 10px;\n left: 5px;\n background-color: dimgrey;\n color: white;\n padding: 4px 6px;\n font-size: 12px;\n border-radius: 3px;\n font-family: monospace;\n box-shadow: 1px 1px 1px 0px rgba(0,0,0,0.75);\n opacity: ${this.options.rule.opacity};\n }\n `,s=document.createElement("style");s.id=t,s.textContent=i,document.head.appendChild(s)}static createRule(){const t=document.createElement("div");t.className="JsWidthBreakpoints-rule",this.breakpoints.forEach((i=>{const s=document.createElement("div");s.className="JsWidthBreakpoints-rule-line",s.style.left=`${i}px`;const e=document.createElement("div");e.className="JsWidthBreakpoints-rule-label",e.textContent=`${i}px`,e.style.left=`${i+5}px`,t.appendChild(s),t.appendChild(e)})),document.body.appendChild(t)}}window.JsWidthBreakpoints=JsWidthBreakpoints;
|
package/gulpfile.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const gulp = require('gulp');
|
|
4
|
+
const merge = require('merge-stream');
|
|
4
5
|
const concat = require('gulp-concat');
|
|
5
6
|
const terser = require('gulp-terser');
|
|
6
7
|
const header = require('gulp-header');
|
|
@@ -8,7 +9,6 @@ const rename = require('gulp-rename');
|
|
|
8
9
|
const package = require('./package.json');
|
|
9
10
|
const settingsPath = path.join(__dirname, '.vscode', 'settings.json');
|
|
10
11
|
|
|
11
|
-
// Cabeçalho personalizado
|
|
12
12
|
const banner = `/**
|
|
13
13
|
* JsWidthBreakpoints - A lightweight, vanilla JavaScript library for handling responsive breakpoints with dynamic CSS classes and visual rules.
|
|
14
14
|
* Version: ${package.version}
|
|
@@ -19,15 +19,22 @@ const banner = `/**
|
|
|
19
19
|
*/
|
|
20
20
|
`;
|
|
21
21
|
|
|
22
|
-
// Tarefa principal: compila e minifica o código
|
|
23
22
|
function build() {
|
|
24
|
-
|
|
25
|
-
.src('src/JsWidthBreakpoints.js')
|
|
26
|
-
.pipe(concat('JsWidthBreakpoints.js'))
|
|
27
|
-
.pipe(
|
|
28
|
-
.pipe(
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
const rawStream = gulp
|
|
24
|
+
.src('src/JsWidthBreakpoints.js')
|
|
25
|
+
.pipe(concat('JsWidthBreakpoints.js'))
|
|
26
|
+
.pipe(header(banner))
|
|
27
|
+
.pipe(gulp.dest('dist'));
|
|
28
|
+
|
|
29
|
+
const minStream = gulp
|
|
30
|
+
.src('src/JsWidthBreakpoints.js')
|
|
31
|
+
.pipe(concat('JsWidthBreakpoints.js'))
|
|
32
|
+
.pipe(terser())
|
|
33
|
+
.pipe(rename({ suffix: '.min' }))
|
|
34
|
+
.pipe(header(banner))
|
|
35
|
+
.pipe(gulp.dest('dist'));
|
|
36
|
+
|
|
37
|
+
return merge(rawStream, minStream);
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
async function updateStatusBar() {
|
|
@@ -45,6 +52,5 @@ async function updateStatusBar() {
|
|
|
45
52
|
await Promise.resolve();
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
// Tarefa padrão: executa a tarefa de build
|
|
49
55
|
exports.default = build;
|
|
50
56
|
exports.updateStatusBar = updateStatusBar;
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jswidthbreakpoints",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A lightweight, vanilla JavaScript library for handling responsive breakpoints with dynamic CSS classes and visual rules.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"gulp-concat": "^2.6.1",
|
|
26
26
|
"gulp-header": "^2.0.9",
|
|
27
27
|
"gulp-rename": "^2.0.0",
|
|
28
|
-
"gulp-terser": "^2.1.0"
|
|
28
|
+
"gulp-terser": "^2.1.0",
|
|
29
|
+
"merge-stream": "^2.0.0"
|
|
29
30
|
}
|
|
30
31
|
}
|
|
@@ -1,43 +1,59 @@
|
|
|
1
1
|
class JsWidthBreakpoints {
|
|
2
2
|
// Default settings
|
|
3
3
|
static defaults = {
|
|
4
|
-
widths: [], // Array of breakpoints (e.g., [400, 600, 800])
|
|
5
|
-
onBreakPoint: null, // Callback
|
|
6
|
-
applyClasses: true, //
|
|
7
|
-
classPrefix: 'width-', // Prefix for CSS classes
|
|
8
|
-
rule: {
|
|
4
|
+
widths: [], // Array of breakpoints in pixels (e.g., [400, 600, 800, 1200])
|
|
5
|
+
onBreakPoint: null, // Callback function when breakpoint changes
|
|
6
|
+
applyClasses: true, // Whether to apply CSS classes to <body>
|
|
7
|
+
classPrefix: 'width-', // Prefix for generated CSS classes
|
|
8
|
+
rule: {
|
|
9
9
|
show: false, // Whether to display the rule
|
|
10
10
|
opacity: 1, // Opacity of the rule
|
|
11
11
|
color: 'red', // Color of the rule
|
|
12
12
|
},
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// Flag to prevent multiple initializations
|
|
16
|
+
static _isInitialized = false;
|
|
17
|
+
|
|
15
18
|
// Initialize the library
|
|
16
19
|
static init(options = {}) {
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
if (this._isInitialized) {
|
|
21
|
+
console.warn('JsWidthBreakpoints is already initialized. Ignoring subsequent init call.');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Deep merge only on rule object
|
|
26
|
+
const userOptions = options || {};
|
|
27
|
+
const mergedRule = { ...this.defaults.rule, ...(userOptions.rule || {}) };
|
|
28
|
+
|
|
29
|
+
this.options = {
|
|
30
|
+
...this.defaults,
|
|
31
|
+
...userOptions,
|
|
32
|
+
rule: mergedRule,
|
|
33
|
+
};
|
|
19
34
|
|
|
20
35
|
// Sort breakpoints in descending order
|
|
21
|
-
this.breakpoints = this.options.widths
|
|
36
|
+
this.breakpoints = [...(this.options.widths || [])]
|
|
37
|
+
.filter(v => Number.isInteger(v) && v > 0)
|
|
38
|
+
.sort((a, b) => b - a);
|
|
22
39
|
|
|
23
|
-
// Store the length of the breakpoints array
|
|
24
40
|
this.breakpoints_length = this.breakpoints.length;
|
|
25
41
|
|
|
26
|
-
//
|
|
27
|
-
this.
|
|
42
|
+
// Key decision: no valid breakpoints → doesn't initialize anything
|
|
43
|
+
if (this.breakpoints_length === 0) {
|
|
44
|
+
console.warn('JsWidthBreakpoints: No valid breakpoints provided. Library will not be activated.');
|
|
45
|
+
this._isInitialized = true;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
28
48
|
|
|
29
|
-
// Get the smallest breakpoint
|
|
30
49
|
this.smallestBreakpoint = this.breakpoints[this.breakpoints_length - 1];
|
|
50
|
+
this.biggestBreakpoint = this.breakpoints[0];
|
|
51
|
+
this.allBreakpointClasses = this.getAllBreakpointClasses();
|
|
31
52
|
|
|
32
53
|
// Check if the callback is a function
|
|
33
54
|
this.hasCallback = typeof this.options.onBreakPoint === 'function';
|
|
34
|
-
|
|
35
55
|
// Get the current window width
|
|
36
56
|
this.currentWidth = this.getWindowWidth();
|
|
37
|
-
|
|
38
|
-
// Get all possible breakpoint class names
|
|
39
|
-
this.allBreakpointClasses = this.getAllBreakpointClasses();
|
|
40
|
-
|
|
41
57
|
// Store the current class name
|
|
42
58
|
this.currentClass = null;
|
|
43
59
|
|
|
@@ -45,24 +61,30 @@ class JsWidthBreakpoints {
|
|
|
45
61
|
this.setupEventListeners();
|
|
46
62
|
|
|
47
63
|
// Check and apply breakpoints immediately
|
|
48
|
-
this.checkBreakpoints(
|
|
64
|
+
this.checkBreakpoints();
|
|
49
65
|
|
|
50
66
|
// Initialize the rule if enabled
|
|
51
67
|
if (this.options.rule.show) {
|
|
52
|
-
this.injectRuleStyles();
|
|
53
|
-
this.createRule();
|
|
68
|
+
this.injectRuleStyles();
|
|
69
|
+
this.createRule();
|
|
54
70
|
}
|
|
71
|
+
|
|
72
|
+
this._isInitialized = true;
|
|
55
73
|
}
|
|
56
74
|
|
|
57
|
-
// Get all
|
|
75
|
+
// Get all possible breakpoint class names
|
|
58
76
|
static getAllBreakpointClasses() {
|
|
77
|
+
if (this.breakpoints_length === 0) return [];
|
|
78
|
+
|
|
59
79
|
const result = [
|
|
60
80
|
`lt${this.smallestBreakpoint}`,
|
|
61
81
|
`gt${this.biggestBreakpoint}`,
|
|
62
82
|
];
|
|
63
83
|
|
|
64
|
-
for (let i =
|
|
65
|
-
|
|
84
|
+
for (let i = 1; i < this.breakpoints_length; i++) {
|
|
85
|
+
const lower = this.breakpoints[i];
|
|
86
|
+
const higher = this.breakpoints[i - 1];
|
|
87
|
+
result.push(`b${lower}a${higher}`);
|
|
66
88
|
}
|
|
67
89
|
|
|
68
90
|
return result;
|
|
@@ -70,105 +92,100 @@ class JsWidthBreakpoints {
|
|
|
70
92
|
|
|
71
93
|
// Get the current window width
|
|
72
94
|
static getWindowWidth() {
|
|
73
|
-
return window.innerWidth;
|
|
95
|
+
return window.innerWidth;
|
|
74
96
|
}
|
|
75
97
|
|
|
76
98
|
// Set up the window resize listener
|
|
77
99
|
static setupEventListeners() {
|
|
78
|
-
window.addEventListener('resize', () =>
|
|
79
|
-
this.checkBreakpoints();
|
|
80
|
-
});
|
|
100
|
+
window.addEventListener('resize', () => this.checkBreakpoints());
|
|
81
101
|
}
|
|
82
102
|
|
|
83
|
-
//
|
|
84
|
-
static checkBreakpoints(
|
|
103
|
+
// Main logic - simplified and callback always works
|
|
104
|
+
static checkBreakpoints() {
|
|
85
105
|
const newWidth = this.getWindowWidth();
|
|
106
|
+
this.currentWidth = newWidth;
|
|
107
|
+
|
|
108
|
+
const breakpoint = this.getCurrentBreakpoint();
|
|
86
109
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.
|
|
90
|
-
|
|
110
|
+
if (breakpoint !== this.currentClass) {
|
|
111
|
+
const oldBreakpoint = this.currentClass || '';
|
|
112
|
+
this.currentClass = breakpoint;
|
|
113
|
+
|
|
114
|
+
// Execute the callback if defined
|
|
115
|
+
if (this.hasCallback) {
|
|
116
|
+
this.options.onBreakPoint({
|
|
117
|
+
oldBreakpoint,
|
|
118
|
+
currentWidth: newWidth,
|
|
119
|
+
currentBreakpoint: breakpoint,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
91
122
|
|
|
92
|
-
// Apply
|
|
123
|
+
// Apply classes only if enabled
|
|
93
124
|
if (this.options.applyClasses) {
|
|
94
|
-
|
|
95
|
-
if (breakpoint !== this.currentClass) {
|
|
96
|
-
const oldBreakpoint = this.currentClass;
|
|
97
|
-
this.currentClass = breakpoint;
|
|
98
|
-
|
|
99
|
-
// Execute the callback if defined
|
|
100
|
-
if (this.hasCallback) {
|
|
101
|
-
this.options.onBreakPoint({
|
|
102
|
-
oldBreakpoint: oldBreakpoint || '',
|
|
103
|
-
currentWidth: this.currentWidth,
|
|
104
|
-
currentBreakpoint: breakpoint,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Apply CSS classes based on the breakpoint
|
|
109
|
-
this.applyBreakpointClasses(breakpoint);
|
|
110
|
-
}
|
|
125
|
+
this.applyBreakpointClasses(breakpoint);
|
|
111
126
|
}
|
|
112
127
|
}
|
|
113
128
|
}
|
|
114
129
|
|
|
115
|
-
// Get the current breakpoint
|
|
116
130
|
static getCurrentBreakpoint() {
|
|
117
|
-
if (this.
|
|
131
|
+
if (this.breakpoints_length === 0) return null;
|
|
132
|
+
|
|
133
|
+
const w = this.currentWidth;
|
|
134
|
+
|
|
135
|
+
if (w <= this.smallestBreakpoint) {
|
|
118
136
|
return `lt${this.smallestBreakpoint}`;
|
|
119
|
-
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (w >= this.biggestBreakpoint) {
|
|
120
140
|
return `gt${this.biggestBreakpoint}`;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (let i = 1; i < this.breakpoints_length; i++) {
|
|
144
|
+
const higher = this.breakpoints[i - 1];
|
|
145
|
+
const lower = this.breakpoints[i];
|
|
146
|
+
|
|
147
|
+
if (w >= lower && w < higher) {
|
|
148
|
+
return `b${lower}a${higher}`;
|
|
126
149
|
}
|
|
127
150
|
}
|
|
151
|
+
|
|
128
152
|
return null;
|
|
129
153
|
}
|
|
130
154
|
|
|
131
|
-
// Apply CSS classes based on the breakpoint
|
|
132
155
|
static applyBreakpointClasses(breakpoint) {
|
|
133
156
|
const body = document.body;
|
|
134
|
-
const
|
|
157
|
+
const prefix = this.options.classPrefix;
|
|
135
158
|
|
|
136
|
-
// Remove
|
|
159
|
+
// Remove all possible classes first
|
|
137
160
|
this.allBreakpointClasses.forEach((cls) => {
|
|
138
|
-
body.classList.remove(`${
|
|
161
|
+
body.classList.remove(`${prefix}${cls}`);
|
|
139
162
|
});
|
|
140
163
|
|
|
141
|
-
// Add
|
|
164
|
+
// Add current one
|
|
142
165
|
if (breakpoint) {
|
|
143
|
-
body.classList.add(`${
|
|
166
|
+
body.classList.add(`${prefix}${breakpoint}`);
|
|
144
167
|
}
|
|
145
168
|
}
|
|
146
169
|
|
|
147
|
-
// Inject CSS styles for the rule
|
|
148
170
|
static injectRuleStyles() {
|
|
149
171
|
const styleId = 'jsWidthBreakpointsRuleStyles';
|
|
150
|
-
if (document.getElementById(styleId)) return;
|
|
172
|
+
if (document.getElementById(styleId)) return;
|
|
151
173
|
|
|
152
174
|
const styles = `
|
|
153
175
|
.JsWidthBreakpoints-rule {
|
|
154
176
|
position: fixed;
|
|
155
|
-
top: 0;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
height: 100%;
|
|
159
|
-
pointer-events: none; /* Ensure the rule doesn't interfere with clicks */
|
|
177
|
+
top: 0; left: 0;
|
|
178
|
+
width: 100%; height: 100%;
|
|
179
|
+
pointer-events: none;
|
|
160
180
|
z-index: 1000;
|
|
161
181
|
}
|
|
162
|
-
|
|
163
182
|
.JsWidthBreakpoints-rule-line {
|
|
164
183
|
position: absolute;
|
|
165
|
-
top: 0;
|
|
166
|
-
height: 100%;
|
|
184
|
+
top: 0; height: 100%;
|
|
167
185
|
width: 1px;
|
|
168
186
|
background-color: ${this.options.rule.color};
|
|
169
187
|
opacity: ${this.options.rule.opacity};
|
|
170
188
|
}
|
|
171
|
-
|
|
172
189
|
.JsWidthBreakpoints-rule-label {
|
|
173
190
|
position: absolute;
|
|
174
191
|
top: 10px;
|
|
@@ -184,18 +201,17 @@ class JsWidthBreakpoints {
|
|
|
184
201
|
}
|
|
185
202
|
`;
|
|
186
203
|
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
document.head.appendChild(
|
|
204
|
+
const style = document.createElement('style');
|
|
205
|
+
style.id = styleId;
|
|
206
|
+
style.textContent = styles;
|
|
207
|
+
document.head.appendChild(style);
|
|
191
208
|
}
|
|
192
209
|
|
|
193
|
-
// Create the rule (régua)
|
|
194
210
|
static createRule() {
|
|
195
211
|
const ruleContainer = document.createElement('div');
|
|
196
212
|
ruleContainer.className = 'JsWidthBreakpoints-rule';
|
|
197
213
|
|
|
198
|
-
//
|
|
214
|
+
// Lines from largest to smallest (visual order)
|
|
199
215
|
this.breakpoints.forEach((width) => {
|
|
200
216
|
const line = document.createElement('div');
|
|
201
217
|
line.className = 'JsWidthBreakpoints-rule-line';
|
|
@@ -204,7 +220,7 @@ class JsWidthBreakpoints {
|
|
|
204
220
|
const label = document.createElement('div');
|
|
205
221
|
label.className = 'JsWidthBreakpoints-rule-label';
|
|
206
222
|
label.textContent = `${width}px`;
|
|
207
|
-
label.style.left = `${width + 5}px`;
|
|
223
|
+
label.style.left = `${width + 5}px`;
|
|
208
224
|
|
|
209
225
|
ruleContainer.appendChild(line);
|
|
210
226
|
ruleContainer.appendChild(label);
|
|
@@ -215,5 +231,5 @@ class JsWidthBreakpoints {
|
|
|
215
231
|
}
|
|
216
232
|
}
|
|
217
233
|
|
|
218
|
-
// Expose
|
|
234
|
+
// Expose globally
|
|
219
235
|
window.JsWidthBreakpoints = JsWidthBreakpoints;
|