@keenmate/pure-css 1.0.0-rc03 → 1.0.0-rc05

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.
@@ -17,16 +17,16 @@ p {
17
17
  }
18
18
 
19
19
  :where(a) {
20
- color: var(--pa-link-color);
20
+ color: var(--pc-link-color);
21
21
  text-decoration: underline;
22
22
  }
23
23
 
24
24
  :where(a:hover) {
25
- color: var(--pa-link-color-hover);
25
+ color: var(--pc-link-color-hover);
26
26
  }
27
27
 
28
28
  :where(a:visited) {
29
- color: var(--pa-link-color-visited);
29
+ color: var(--pc-link-color-visited);
30
30
  }
31
31
 
32
32
  ul, ol {
@@ -79,8 +79,8 @@ body {
79
79
  padding: 0;
80
80
  font-family: var(--base-font-family);
81
81
  font-size: 1.6rem;
82
- color: var(--pa-text-color-1);
83
- background-color: var(--pa-main-bg);
82
+ color: var(--pc-text-color-1);
83
+ background-color: var(--pc-main-bg);
84
84
  line-height: 1.5;
85
85
  }
86
86
 
@@ -5,28 +5,28 @@
5
5
  }
6
6
 
7
7
  *::-webkit-scrollbar-track {
8
- background: var(--pa-main-bg);
9
- border-radius: var(--pa-border-radius-sm);
8
+ background: var(--pc-main-bg);
9
+ border-radius: var(--pc-border-radius-sm);
10
10
  }
11
11
 
12
12
  *::-webkit-scrollbar-thumb {
13
- background: var(--pa-border-color);
14
- border-radius: var(--pa-border-radius-sm);
15
- border: 1px solid var(--pa-main-bg);
13
+ background: var(--pc-border-color);
14
+ border-radius: var(--pc-border-radius-sm);
15
+ border: 1px solid var(--pc-main-bg);
16
16
  }
17
17
  *::-webkit-scrollbar-thumb:hover {
18
- background: var(--pa-accent);
18
+ background: var(--pc-accent);
19
19
  }
20
20
  *::-webkit-scrollbar-thumb:active {
21
- background: var(--pa-accent-hover);
21
+ background: var(--pc-accent-hover);
22
22
  }
23
23
 
24
24
  *::-webkit-scrollbar-corner {
25
- background: var(--pa-main-bg);
25
+ background: var(--pc-main-bg);
26
26
  }
27
27
 
28
28
  /* Firefox */
29
29
  * {
30
30
  scrollbar-width: thin;
31
- scrollbar-color: var(--pa-border-color) var(--pa-main-bg);
31
+ scrollbar-color: var(--pc-border-color) var(--pc-main-bg);
32
32
  }
@@ -1357,6 +1357,30 @@
1357
1357
  flex-shrink: 1 !important;
1358
1358
  }
1359
1359
 
1360
+ .flex-1 {
1361
+ flex: 1 1 0% !important;
1362
+ }
1363
+
1364
+ .flex-auto {
1365
+ flex: 1 1 auto !important;
1366
+ }
1367
+
1368
+ .flex-initial {
1369
+ flex: 0 1 auto !important;
1370
+ }
1371
+
1372
+ .flex-none {
1373
+ flex: none !important;
1374
+ }
1375
+
1376
+ .flex-grow {
1377
+ flex-grow: 1 !important;
1378
+ }
1379
+
1380
+ .flex-shrink {
1381
+ flex-shrink: 1 !important;
1382
+ }
1383
+
1360
1384
  .text-center {
1361
1385
  text-align: center !important;
1362
1386
  }
@@ -2052,6 +2076,30 @@
2052
2076
  max-height: 50rem !important;
2053
2077
  }
2054
2078
 
2079
+ .h-full {
2080
+ height: 100% !important;
2081
+ }
2082
+
2083
+ .h-screen {
2084
+ height: 100vh !important;
2085
+ }
2086
+
2087
+ .min-h-full {
2088
+ min-height: 100% !important;
2089
+ }
2090
+
2091
+ .min-h-screen {
2092
+ min-height: 100vh !important;
2093
+ }
2094
+
2095
+ .max-h-full {
2096
+ max-height: 100% !important;
2097
+ }
2098
+
2099
+ .max-h-screen {
2100
+ max-height: 100vh !important;
2101
+ }
2102
+
2055
2103
  .minw-5 {
2056
2104
  min-width: 5% !important;
2057
2105
  }
@@ -2461,23 +2509,23 @@
2461
2509
  }
2462
2510
 
2463
2511
  .border {
2464
- border: 1px solid var(--pa-border-color) !important;
2512
+ border: 1px solid var(--pc-border-color) !important;
2465
2513
  }
2466
2514
 
2467
2515
  .border-top {
2468
- border-top: 1px solid var(--pa-border-color) !important;
2516
+ border-top: 1px solid var(--pc-border-color) !important;
2469
2517
  }
2470
2518
 
2471
2519
  .border-right {
2472
- border-right: 1px solid var(--pa-border-color) !important;
2520
+ border-right: 1px solid var(--pc-border-color) !important;
2473
2521
  }
2474
2522
 
2475
2523
  .border-bottom {
2476
- border-bottom: 1px solid var(--pa-border-color) !important;
2524
+ border-bottom: 1px solid var(--pc-border-color) !important;
2477
2525
  }
2478
2526
 
2479
2527
  .border-left {
2480
- border-left: 1px solid var(--pa-border-color) !important;
2528
+ border-left: 1px solid var(--pc-border-color) !important;
2481
2529
  }
2482
2530
 
2483
2531
  .border-0 {
@@ -2517,67 +2565,67 @@
2517
2565
  }
2518
2566
 
2519
2567
  .text-primary {
2520
- color: var(--pa-accent) !important;
2568
+ color: var(--pc-accent) !important;
2521
2569
  }
2522
2570
 
2523
2571
  .text-success {
2524
- color: var(--pa-success-text) !important;
2572
+ color: var(--pc-success-text) !important;
2525
2573
  }
2526
2574
 
2527
2575
  .text-danger {
2528
- color: var(--pa-danger-text) !important;
2576
+ color: var(--pc-danger-text) !important;
2529
2577
  }
2530
2578
 
2531
2579
  .text-warning {
2532
- color: var(--pa-warning-text) !important;
2580
+ color: var(--pc-warning-text) !important;
2533
2581
  }
2534
2582
 
2535
2583
  .text-info {
2536
- color: var(--pa-info-text) !important;
2584
+ color: var(--pc-info-text) !important;
2537
2585
  }
2538
2586
 
2539
2587
  .text-color-1 {
2540
- color: var(--pa-color-1) !important;
2588
+ color: var(--pc-color-1) !important;
2541
2589
  }
2542
2590
 
2543
2591
  .text-color-2 {
2544
- color: var(--pa-color-2) !important;
2592
+ color: var(--pc-color-2) !important;
2545
2593
  }
2546
2594
 
2547
2595
  .text-color-3 {
2548
- color: var(--pa-color-3) !important;
2596
+ color: var(--pc-color-3) !important;
2549
2597
  }
2550
2598
 
2551
2599
  .text-color-4 {
2552
- color: var(--pa-color-4) !important;
2600
+ color: var(--pc-color-4) !important;
2553
2601
  }
2554
2602
 
2555
2603
  .text-color-5 {
2556
- color: var(--pa-color-5) !important;
2604
+ color: var(--pc-color-5) !important;
2557
2605
  }
2558
2606
 
2559
2607
  .text-color-6 {
2560
- color: var(--pa-color-6) !important;
2608
+ color: var(--pc-color-6) !important;
2561
2609
  }
2562
2610
 
2563
2611
  .text-color-7 {
2564
- color: var(--pa-color-7) !important;
2612
+ color: var(--pc-color-7) !important;
2565
2613
  }
2566
2614
 
2567
2615
  .text-color-8 {
2568
- color: var(--pa-color-8) !important;
2616
+ color: var(--pc-color-8) !important;
2569
2617
  }
2570
2618
 
2571
2619
  .text-color-9 {
2572
- color: var(--pa-color-9) !important;
2620
+ color: var(--pc-color-9) !important;
2573
2621
  }
2574
2622
 
2575
2623
  .rounded {
2576
- border-radius: var(--pa-border-radius) !important;
2624
+ border-radius: var(--pc-border-radius) !important;
2577
2625
  }
2578
2626
 
2579
2627
  .rounded-lg {
2580
- border-radius: var(--pa-border-radius-lg) !important;
2628
+ border-radius: var(--pc-border-radius-lg) !important;
2581
2629
  }
2582
2630
 
2583
2631
  .rounded-circle {
@@ -2589,23 +2637,23 @@
2589
2637
  }
2590
2638
 
2591
2639
  .rounded-top {
2592
- border-top-left-radius: var(--pa-border-radius) !important;
2593
- border-top-right-radius: var(--pa-border-radius) !important;
2640
+ border-top-left-radius: var(--pc-border-radius) !important;
2641
+ border-top-right-radius: var(--pc-border-radius) !important;
2594
2642
  }
2595
2643
 
2596
2644
  .rounded-bottom {
2597
- border-bottom-left-radius: var(--pa-border-radius) !important;
2598
- border-bottom-right-radius: var(--pa-border-radius) !important;
2645
+ border-bottom-left-radius: var(--pc-border-radius) !important;
2646
+ border-bottom-right-radius: var(--pc-border-radius) !important;
2599
2647
  }
2600
2648
 
2601
2649
  .rounded-left {
2602
- border-top-left-radius: var(--pa-border-radius) !important;
2603
- border-bottom-left-radius: var(--pa-border-radius) !important;
2650
+ border-top-left-radius: var(--pc-border-radius) !important;
2651
+ border-bottom-left-radius: var(--pc-border-radius) !important;
2604
2652
  }
2605
2653
 
2606
2654
  .rounded-right {
2607
- border-top-right-radius: var(--pa-border-radius) !important;
2608
- border-bottom-right-radius: var(--pa-border-radius) !important;
2655
+ border-top-right-radius: var(--pc-border-radius) !important;
2656
+ border-bottom-right-radius: var(--pc-border-radius) !important;
2609
2657
  }
2610
2658
 
2611
2659
  .shadow-none {
@@ -2768,6 +2816,6 @@
2768
2816
  row-gap: 5rem !important;
2769
2817
  }
2770
2818
 
2771
- .pa-cq {
2819
+ .pc-cq {
2772
2820
  container-type: inline-size;
2773
2821
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keenmate/pure-css",
3
- "version": "1.0.0-rc03",
3
+ "version": "1.0.0-rc05",
4
4
  "description": "The KeenMate CSS foundation — --base-* theming contract, PureCSS grid and utility classes. Extracted from pure-admin-core so docs sites, standalone pages and every web/svelte component share one theming layer.",
5
5
  "style": "dist/css/pure-css.css",
6
6
  "exports": {
@@ -13,11 +13,14 @@
13
13
  "./grid": "./dist/css/grid.css",
14
14
  "./utilities": "./dist/css/utilities.css",
15
15
  "./scss": "./src/scss/pure-css.scss",
16
- "./scss/*": "./src/scss/*"
16
+ "./scss/*": "./src/scss/*",
17
+ "./js": "./src/js/pure-css.js",
18
+ "./js/*": "./src/js/*"
17
19
  },
18
20
  "files": [
19
21
  "dist/",
20
22
  "src/scss/",
23
+ "src/js/",
21
24
  "README.md",
22
25
  "CHANGELOG.md",
23
26
  "LICENSE"
@@ -31,6 +34,12 @@
31
34
  "build:utilities": "sass src/scss/utilities.scss dist/css/utilities.css --no-source-map --silence-deprecation=import",
32
35
  "build": "npm run build:bundle && npm run build:base && npm run build:reboot && npm run build:scrollbars && npm run build:grid && npm run build:utilities",
33
36
  "watch": "sass --watch src/scss/pure-css.scss:dist/css/pure-css.css --silence-deprecation=import",
37
+ "dev": "vite --port 12500",
38
+ "test": "npm run test:e2e",
39
+ "test:e2e": "playwright test",
40
+ "test:e2e:ui": "playwright test --ui",
41
+ "test:e2e:headed": "playwright test --headed",
42
+ "test:e2e:install": "playwright install chromium",
34
43
  "prepublishOnly": "npm run build"
35
44
  },
36
45
  "keywords": [
@@ -50,7 +59,9 @@
50
59
  "sass": "^1.0.0"
51
60
  },
52
61
  "devDependencies": {
53
- "sass": "^1.70.0"
62
+ "@playwright/test": "^1.60.0",
63
+ "sass": "^1.70.0",
64
+ "vite": "^5.4.0"
54
65
  },
55
66
  "repository": {
56
67
  "type": "git",
@@ -62,5 +73,9 @@
62
73
  "homepage": "https://github.com/KeenMate/pure-css#readme",
63
74
  "publishConfig": {
64
75
  "access": "public"
76
+ },
77
+ "allowScripts": {
78
+ "esbuild@0.21.5": true,
79
+ "@parcel/watcher@2.6.0": true
65
80
  }
66
81
  }
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Pure CSS — Container Breakpoint (element-width → named mode, event-driven)
3
+ *
4
+ * The JS counterpart to a CSS container query. A CSS `@container` rule can only
5
+ * SHOW / HIDE — it can never skip work. This watches an element's inline size
6
+ * with a ResizeObserver, maps it to a NAMED mode from author-declared width
7
+ * thresholds, and EMITS a change only when the mode actually flips. A framework
8
+ * wrapper turns that event into conditional rendering — so the branches for
9
+ * other modes are never MOUNTED (no off-screen Chart.js instance, no eager data
10
+ * fetch, no shadow-DOM widget built to be immediately hidden).
11
+ *
12
+ * This is the "expensive 2-D swap" tool; `fit.js` remains the "cheap 1-D row
13
+ * fold" tool. The difference is measurement:
14
+ * - fit.js is CONTENT-measured (it renders every variant to read its width),
15
+ * so it can't avoid mounting the losers.
16
+ * - container-breakpoint is THRESHOLD-declared (you name the widths), so the
17
+ * losers never need to exist — which is exactly what lets a wrapper mount
18
+ * on demand.
19
+ *
20
+ * Because it is threshold-declared it does NOT need `container-type` on the
21
+ * element (the ResizeObserver measures the box directly). It reads the element's
22
+ * CONTENT-box inline size, to match `@container inline-size` semantics — so a
23
+ * `data-mode` written here and an `@container` rule agree on width.
24
+ *
25
+ * ── Programmatic API (what a Svelte / vanilla caller uses) ──────────────────
26
+ * var handle = pureCss.components.containerBreakpoint.observe(el, {
27
+ * steps: { compact: 0, comfy: 34, wide: 64 }, // name → MIN inline size
28
+ * unit: 'rem', // 'rem' (default, resolved vs :root font-size) | 'px'
29
+ * hysteresis: 1, // dead-band (in `unit`) to stop boundary flapping
30
+ * attribute: 'data-mode', // reflect the mode here (false to not write any)
31
+ * initial: 'comfy', // mode written synchronously before first measure
32
+ * // (SSR/first-paint default; omit to skip)
33
+ * emitEvent: true // also dispatch a 'pc:breakpoint' CustomEvent on el
34
+ * }, function (mode, prev, detail) { ... }); // cb fires once on settle, then on change
35
+ *
36
+ * handle.current(); // → the current mode string
37
+ * handle.remeasure(); // force a re-evaluate (e.g. after a font swap)
38
+ * handle.destroy(); // disconnect the observer + drop the attribute
39
+ *
40
+ * The callback and the 'pc:breakpoint' event (detail: {mode, prev, width, el})
41
+ * are two faces of the same signal — use the callback from JS, the event from a
42
+ * framework hook (Phoenix LiveView, etc.) that can't take a closure.
43
+ *
44
+ * ── Declarative API (zero-framework / keen bridge) ──────────────────────────
45
+ * Wire it from markup — no JS call site — so CSS can key off [data-mode] and a
46
+ * LiveView hook can listen for 'pc:breakpoint':
47
+ *
48
+ * <div data-pc-breakpoints='{"compact":0,"comfy":34,"wide":64}'
49
+ * data-pc-breakpoint-initial="comfy">
50
+ * <div data-pc-show="wide">…rich…</div> <!-- .d-none unless mode = wide -->
51
+ * <div data-pc-show="compact comfy">…lite…</div>
52
+ * </div>
53
+ *
54
+ * pureCss.components.containerBreakpoint.initAll(); // or .init(el)
55
+ *
56
+ * data-pc-show="a b …" — a descendant appears ONLY in the listed modes; in any
57
+ * other mode the engine toggles the shared `.d-none` utility onto it (a CLASS,
58
+ * not inline display — so it reverts to its natural stylesheet display when
59
+ * shown, and you can watch the class hop in devtools, same idea as fit.js's
60
+ * `pc-fit-hidden`). Override the class per-call with opts.hiddenClass or globally
61
+ * via pureCss.config.containerBreakpoint.hiddenClass. Elements without
62
+ * data-pc-show are never touched — pure CSS `[data-mode]` styling still works
63
+ * alongside it.
64
+ *
65
+ * Optional attrs: data-pc-breakpoint-unit ("rem"|"px"),
66
+ * data-pc-breakpoint-hysteresis (number), data-pc-breakpoint-attr (attr name to
67
+ * reflect into, default "data-mode").
68
+ *
69
+ * Public API (window.pureCss.components.containerBreakpoint):
70
+ * observe(el, opts, cb) — wire one element; returns a handle (idempotent per call)
71
+ * init(el) — declarative wire from data-pc-breakpoints (idempotent)
72
+ * initAll(scope) — declarative wire every [data-pc-breakpoints] under scope
73
+ * relayoutAll() — force a re-measure of every declaratively-wired element
74
+ */
75
+ (function () {
76
+ 'use strict';
77
+
78
+ var SELECTOR = '[data-pc-breakpoints]';
79
+
80
+ // :root font-size in px, for resolving rem thresholds against the live base
81
+ // (pure-admin ships 10px, but resolve rather than assume so a consumer that
82
+ // changes it stays correct). Falls back to 16 if unreadable.
83
+ function rootFontPx() {
84
+ try {
85
+ var n = parseFloat(getComputedStyle(document.documentElement).fontSize);
86
+ return (!isNaN(n) && n > 0) ? n : 16;
87
+ } catch (e) { return 16; }
88
+ }
89
+
90
+ // Normalise `steps` (object {name:min} or array [{name,min}]) into an array of
91
+ // { name, min } sorted ASCENDING by min. min is in the caller's unit.
92
+ function normSteps(steps) {
93
+ var out = [];
94
+ if (Array.isArray(steps)) {
95
+ steps.forEach(function (s) {
96
+ if (s && s.name != null && isFinite(s.min)) out.push({ name: String(s.name), min: +s.min });
97
+ });
98
+ } else if (steps && typeof steps === 'object') {
99
+ Object.keys(steps).forEach(function (name) {
100
+ var v = parseFloat(steps[name]);
101
+ if (!isNaN(v)) out.push({ name: name, min: v });
102
+ });
103
+ }
104
+ out.sort(function (a, b) { return a.min - b.min; });
105
+ return out;
106
+ }
107
+
108
+ // Largest step whose min <= width (px). Returns its index; 0 (the floor) when
109
+ // the element is narrower than every threshold.
110
+ function candidateIndex(widthPx, stepsPx) {
111
+ var idx = 0;
112
+ for (var i = 0; i < stepsPx.length; i++) {
113
+ if (widthPx >= stepsPx[i].min) idx = i; else break;
114
+ }
115
+ return idx;
116
+ }
117
+
118
+ // Resolve the settled mode index with a dead-band so a width parked on a
119
+ // boundary doesn't flip every frame:
120
+ // - moving UP: accept the higher step only once width clears its min by band
121
+ // - moving DOWN: accept a lower step only once width drops below the CURRENT
122
+ // step's min by band
123
+ // First evaluation (curIdx == null) takes the plain candidate — no band, so the
124
+ // initial mode is a pure function of width.
125
+ function settleIndex(widthPx, stepsPx, curIdx, bandPx) {
126
+ var cand = candidateIndex(widthPx, stepsPx);
127
+ if (curIdx == null || cand === curIdx) return cand;
128
+ if (cand > curIdx) {
129
+ return (widthPx >= stepsPx[cand].min + bandPx) ? cand : curIdx;
130
+ }
131
+ // cand < curIdx
132
+ return (widthPx < stepsPx[curIdx].min - bandPx) ? cand : curIdx;
133
+ }
134
+
135
+ function observe(el, opts, cb) {
136
+ if (!el || el.nodeType !== 1) return null;
137
+ opts = opts || {};
138
+
139
+ var steps = normSteps(opts.steps);
140
+ if (!steps.length) return null; // nothing to switch between
141
+
142
+ var unit = opts.unit === 'px' ? 'px' : 'rem';
143
+ var hysteresis = isFinite(opts.hysteresis) ? +opts.hysteresis
144
+ : ((window.pureCss && window.pureCss.config && window.pureCss.config.containerBreakpoint
145
+ && window.pureCss.config.containerBreakpoint.hysteresis) || 0);
146
+ var attribute = opts.attribute === false ? null : (opts.attribute || 'data-mode');
147
+ var emitEvent = opts.emitEvent !== false;
148
+ var hiddenClass = opts.hiddenClass
149
+ || (window.pureCss && window.pureCss.config && window.pureCss.config.containerBreakpoint
150
+ && window.pureCss.config.containerBreakpoint.hiddenClass)
151
+ || 'd-none';
152
+
153
+ var curIdx = null; // settled step index; null until first measure
154
+ var curMode = null;
155
+
156
+ // Convert the declared thresholds + band into px for comparison. Recomputed
157
+ // per measure so a runtime root-font-size change is honoured (rem unit only).
158
+ function toPx() {
159
+ var base = unit === 'rem' ? rootFontPx() : 1;
160
+ return {
161
+ steps: steps.map(function (s) { return { name: s.name, min: s.min * base }; }),
162
+ band: hysteresis * base
163
+ };
164
+ }
165
+
166
+ // Toggle the shared hidden class on [data-pc-show] descendants: an element
167
+ // stays visible only in the modes listed in its data-pc-show; in any other
168
+ // mode it gets `hiddenClass`. A class (not inline display) so it reverts to
169
+ // its natural display when shown — and is visible "jumping" in devtools.
170
+ function applyVisibility(mode) {
171
+ if (!hiddenClass) return;
172
+ var shown = el.querySelectorAll('[data-pc-show]');
173
+ for (var i = 0; i < shown.length; i++) {
174
+ var tokens = (shown[i].getAttribute('data-pc-show') || '').split(/\s+/);
175
+ shown[i].classList.toggle(hiddenClass, tokens.indexOf(mode) === -1);
176
+ }
177
+ }
178
+
179
+ function reflect(mode) {
180
+ if (attribute) el.setAttribute(attribute, mode);
181
+ applyVisibility(mode);
182
+ }
183
+
184
+ // Optional synchronous default before the observer's first callback — lets a
185
+ // wrapper render a sane branch on first paint / SSR hydration.
186
+ if (opts.initial != null) {
187
+ curMode = String(opts.initial);
188
+ curIdx = -1; // sentinel: "have a provisional mode, but width not yet read"
189
+ reflect(curMode);
190
+ }
191
+
192
+ function evaluate(widthPx) {
193
+ var p = toPx();
194
+ // Treat the provisional `initial` as "no settled index yet" for the band.
195
+ var fromIdx = (curIdx == null || curIdx < 0) ? null : curIdx;
196
+ var nextIdx = settleIndex(widthPx, p.steps, fromIdx, p.band);
197
+ var nextMode = p.steps[nextIdx].name;
198
+ if (nextMode === curMode && curIdx === nextIdx) return;
199
+ var prev = curMode;
200
+ curIdx = nextIdx;
201
+ curMode = nextMode;
202
+ reflect(curMode);
203
+ var detail = { mode: curMode, prev: prev, width: widthPx, el: el };
204
+ if (typeof cb === 'function') {
205
+ try { cb(curMode, prev, detail); }
206
+ catch (e) { if (window.pureCss && window.pureCss.debug) window.pureCss.debug.log('container-breakpoint', 'callback threw', e); }
207
+ }
208
+ if (emitEvent && typeof CustomEvent === 'function') {
209
+ el.dispatchEvent(new CustomEvent('pc:breakpoint', { detail: detail, bubbles: false }));
210
+ }
211
+ }
212
+
213
+ // Content-box inline size, matching @container inline-size. Prefer the
214
+ // observer entry's contentBoxSize; fall back to clientWidth minus padding.
215
+ function widthFromEntry(entry) {
216
+ if (entry && entry.contentBoxSize) {
217
+ var box = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize;
218
+ if (box && isFinite(box.inlineSize)) return box.inlineSize;
219
+ }
220
+ if (entry && entry.contentRect) return entry.contentRect.width;
221
+ var cs = getComputedStyle(el);
222
+ return el.clientWidth - (parseFloat(cs.paddingLeft) || 0) - (parseFloat(cs.paddingRight) || 0);
223
+ }
224
+
225
+ var ro = null;
226
+ if (typeof ResizeObserver !== 'undefined') {
227
+ ro = new ResizeObserver(function (entries) {
228
+ for (var i = 0; i < entries.length; i++) {
229
+ if (entries[i].target === el) { evaluate(widthFromEntry(entries[i])); return; }
230
+ }
231
+ evaluate(widthFromEntry(null));
232
+ });
233
+ ro.observe(el);
234
+ } else {
235
+ // No ResizeObserver: settle once now, and follow the shared viewport source.
236
+ evaluate(widthFromEntry(null));
237
+ if (window.pureCss && window.pureCss.events) {
238
+ var off = window.pureCss.events.on('viewport:resize', function () { evaluate(widthFromEntry(null)); });
239
+ ro = { disconnect: off };
240
+ }
241
+ }
242
+
243
+ return {
244
+ current: function () { return curMode; },
245
+ remeasure: function () { evaluate(widthFromEntry(null)); },
246
+ destroy: function () {
247
+ if (ro && ro.disconnect) ro.disconnect();
248
+ if (attribute) el.removeAttribute(attribute);
249
+ if (hiddenClass) {
250
+ var shown = el.querySelectorAll('[data-pc-show]');
251
+ for (var i = 0; i < shown.length; i++) shown[i].classList.remove(hiddenClass);
252
+ }
253
+ el.__paCbHandle = null;
254
+ }
255
+ };
256
+ }
257
+
258
+ // Declarative: read config off data-* attributes and observe.
259
+ function init(el) {
260
+ if (!el || el.__paCbHandle) return el && el.__paCbHandle;
261
+ var raw = el.getAttribute('data-pc-breakpoints');
262
+ if (!raw) return null;
263
+ var steps;
264
+ try { steps = JSON.parse(raw); }
265
+ catch (e) {
266
+ if (window.pureCss && window.pureCss.debug) window.pureCss.debug.log('container-breakpoint', 'bad data-pc-breakpoints JSON', raw, e);
267
+ return null;
268
+ }
269
+ var opts = {
270
+ steps: steps,
271
+ unit: el.getAttribute('data-pc-breakpoint-unit') || 'rem',
272
+ attribute: el.getAttribute('data-pc-breakpoint-attr') || 'data-mode',
273
+ initial: el.getAttribute('data-pc-breakpoint-initial') || undefined
274
+ };
275
+ var hy = el.getAttribute('data-pc-breakpoint-hysteresis');
276
+ if (hy != null && hy !== '') opts.hysteresis = parseFloat(hy);
277
+ var handle = observe(el, opts);
278
+ if (handle) el.__paCbHandle = handle;
279
+ return handle;
280
+ }
281
+
282
+ function initAll(scope) {
283
+ var root = scope || document;
284
+ var els = root.querySelectorAll(SELECTOR);
285
+ for (var i = 0; i < els.length; i++) init(els[i]);
286
+ }
287
+
288
+ function relayoutAll() {
289
+ var els = document.querySelectorAll(SELECTOR);
290
+ for (var i = 0; i < els.length; i++) {
291
+ if (els[i].__paCbHandle) els[i].__paCbHandle.remeasure();
292
+ }
293
+ }
294
+
295
+ var pa = (window.pureCss = window.pureCss || {});
296
+ (pa.components = pa.components || {}).containerBreakpoint = {
297
+ observe: observe,
298
+ init: init,
299
+ initAll: initAll,
300
+ relayoutAll: relayoutAll
301
+ };
302
+
303
+ if (document.readyState === 'loading') {
304
+ document.addEventListener('DOMContentLoaded', function () { initAll(); });
305
+ } else {
306
+ initAll();
307
+ }
308
+ })();