@efolusi/meridian 1.5.1 → 1.5.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/ai/Player.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import React from 'react';
3
- import { injectEfCss } from "../forms/Button.js";
3
+ import { injectEfCss, cssPct } from "../forms/Button.js";
4
4
  import { Icon } from "../icons/Icon.js";
5
5
  const CSS = `
6
6
  .ef-player{display:flex;flex-direction:column;gap:10px;padding:14px;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-card);font-family:var(--font-sans)}
@@ -155,7 +155,7 @@ export const Player = /*#__PURE__*/React.forwardRef(function Player({
155
155
  key: i,
156
156
  className: `ef-player__bar${!dur && playing ? ' ef-player__bar--loading' : (i + 0.5) / bars.length <= ratio ? ' ef-player__bar--played' : ''}`,
157
157
  style: {
158
- height: Math.max(8, p * 100) + '%',
158
+ height: cssPct(Math.max(8, p * 100)),
159
159
  animationDelay: !dur ? i * 30 + 'ms' : undefined
160
160
  }
161
161
  }))), /*#__PURE__*/React.createElement("div", {
package/ai/UsageMeter.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  import React from 'react';
4
- import { injectEfCss } from "../forms/Button.js";
4
+ import { injectEfCss, cssPct } from "../forms/Button.js";
5
5
  const CSS = `
6
6
  .ef-usage{display:flex;flex-direction:column;gap:7px}
7
7
  .ef-usage__row{display:flex;align-items:baseline;gap:8px}
@@ -71,7 +71,7 @@ export function UsageMeter({
71
71
  }, /*#__PURE__*/React.createElement("span", {
72
72
  className: "ef-usage__fill",
73
73
  style: {
74
- width: Math.min(100, (animated ? shownRatio : ratio) * 100) + '%',
74
+ width: cssPct(Math.min(100, (animated ? shownRatio : ratio) * 100)),
75
75
  display: 'block'
76
76
  }
77
77
  })), hint || cost ? /*#__PURE__*/React.createElement("div", {
package/data/BarChart.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  import React from 'react';
4
- import { injectEfCss } from "../forms/Button.js";
4
+ import { injectEfCss, cssPct } from "../forms/Button.js";
5
5
  const CSS = `
6
6
  .ef-bars{display:flex;align-items:flex-end;gap:3px;width:100%}
7
7
  .ef-bars__bar{flex:1;min-width:3px;border-radius:2px 2px 0 0;background:var(--sand-200);transition:background var(--dur-fast) var(--ease-out)}
@@ -34,7 +34,7 @@ export function BarChart({
34
34
  key: i,
35
35
  className: `ef-bars__bar${i >= vals.length - highlightLast ? ' ef-bars__bar--hi' : ''}`,
36
36
  style: {
37
- height: Math.max(2, v / max * 100) + '%'
37
+ height: cssPct(Math.max(2, v / max * 100))
38
38
  },
39
39
  title: (data[i] && data[i].label ? data[i].label + ' · ' : '') + (formatValue ? formatValue(v) : v.toLocaleString())
40
40
  }))), labels && labels.length ? /*#__PURE__*/React.createElement("div", {
package/data/LineChart.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  import React from 'react';
4
- import { injectEfCss } from "../forms/Button.js";
4
+ import { injectEfCss, cssPct } from "../forms/Button.js";
5
5
  const CSS = `
6
6
  .ef-linechart{position:relative}
7
7
  .ef-linechart__tip{position:absolute;transform:translate(-50%,-130%);background:var(--surface-inverse);color:var(--text-inverse);font-size:11px;font-weight:500;padding:4px 8px;border-radius:6px;white-space:nowrap;pointer-events:none;z-index:5}
@@ -79,8 +79,8 @@ export function LineChart({
79
79
  })), hov != null && /*#__PURE__*/React.createElement("div", {
80
80
  className: "ef-linechart__tip",
81
81
  style: {
82
- left: x(hov) / W * 100 + '%',
83
- top: y(data[hov].value) / H * 100 + '%'
82
+ left: cssPct(x(hov) / W * 100),
83
+ top: cssPct(y(data[hov].value) / H * 100)
84
84
  }
85
85
  }, data[hov].label, data[hov].label ? ' · ' : '', format ? format(data[hov].value) : data[hov].value.toLocaleString()));
86
86
  }
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
3
3
  import React from 'react';
4
- import { injectEfCss } from "../forms/Button.js";
4
+ import { injectEfCss, cssPct } from "../forms/Button.js";
5
5
  const CSS = `
6
6
  .ef-resizable{display:flex;width:100%;height:100%;min-height:0;min-width:0}
7
7
  .ef-resizable--vertical{flex-direction:column}
@@ -70,7 +70,7 @@ export function Resizable({
70
70
  }), /*#__PURE__*/React.createElement("div", {
71
71
  className: "ef-resizable__pane",
72
72
  style: {
73
- flexBasis: ratio * 100 + '%',
73
+ flexBasis: cssPct(ratio * 100),
74
74
  flexGrow: 0,
75
75
  flexShrink: 0
76
76
  }
package/forms/Button.js CHANGED
@@ -31,6 +31,27 @@ export function injectEfCss(id, text) {
31
31
  s.textContent = text;
32
32
  document.head.appendChild(s);
33
33
  }
34
+ /**
35
+ * Format a number as a CSS percentage that survives server rendering.
36
+ *
37
+ * A bare `value + '%'` writes every digit JavaScript has: `1/3 * 100` becomes
38
+ * `33.33333333333333%`. Browsers keep roughly six significant figures when they
39
+ * parse an inline style, so the DOM reads back `33.3333%`, and React's
40
+ * hydration check compares its own 16-digit string against the browser's
41
+ * truncated one and reports a mismatch on every affected element. The bars in
42
+ * Player, the fill in UsageMeter and the columns in BarChart all hit this.
43
+ *
44
+ * Rounding to three decimals stays well inside what the parser preserves and is
45
+ * far below one pixel at any realistic size. Number-to-string drops trailing
46
+ * zeros on its own, which matters: `33.300%` would be normalised to `33.3%` and
47
+ * reintroduce the very mismatch this avoids.
48
+ *
49
+ * Lowercase, so it stays an internal helper rather than part of the public
50
+ * namespace.
51
+ */
52
+ export function cssPct(value) {
53
+ return Math.round(value * 1000) / 1000 + '%';
54
+ }
34
55
  /**
35
56
  * Point several refs at one node.
36
57
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@efolusi/meridian",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "A general-purpose open-source design system by Efolusi: accessible React components, design tokens, blocks and example apps.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://meridian.efolusi.com",