@opstel/modern-gauges 0.1.0 → 0.1.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/README.md CHANGED
@@ -8,7 +8,6 @@ An animated half-circle SVG gauge component for React. Zero runtime dependencies
8
8
  - Gradient color progression across the arc and tick marks
9
9
  - Automatically generated minor tick marks between major labels
10
10
  - Responsive — fills its container via SVG `viewBox`
11
- - Optional card wrapper with shadow, or render bare into any layout
12
11
 
13
12
  ## Installation
14
13
 
@@ -25,7 +24,7 @@ function Dashboard() {
25
24
  return (
26
25
  <HalfGauge
27
26
  value={72}
28
- ticks={[0, 20, 40, 60, 80, 100]}
27
+ minMax={[0, 20, 40, 60, 80, 100]}
29
28
  colors={['#f44336', '#ffeb3b', '#4caf50']}
30
29
  title="CPU (%)"
31
30
  />
@@ -38,12 +37,9 @@ function Dashboard() {
38
37
  | Prop | Type | Default | Description |
39
38
  |---|---|---|---|
40
39
  | `value` | `number` | — | Current value to display |
41
- | `ticks` | `number[]` | `[0, 5, 10, 15, 20]` | Ordered scale values. First = min, last = max. Labels are rendered at each tick; minor ticks are inserted automatically between them. |
40
+ | `minMax` | `number[]` | `[0, 5, 10, 15, 20]` | Ordered scale values. First = min, last = max. Labels are rendered at each value; minor ticks are inserted automatically between them. |
42
41
  | `colors` | `string[]` | `['#f44336', '#9c27b0']` | Two or more CSS colors forming the gradient from min to max. |
43
42
  | `title` | `string` | — | Optional label displayed below the value |
44
- | `withoutBackground` | `boolean` | `false` | When `true`, renders only the gauge SVG with no card wrapper. Use this when embedding inside your own container. |
45
- | `className` | `string` | — | CSS class applied to the card wrapper (ignored when `withoutBackground` is true) |
46
- | `style` | `object` | — | Inline styles merged into the card wrapper (ignored when `withoutBackground` is true) |
47
43
 
48
44
  ## Examples
49
45
 
@@ -58,39 +54,15 @@ function Dashboard() {
58
54
  ```jsx
59
55
  <HalfGauge
60
56
  value={3500}
61
- ticks={[0, 1000, 2000, 3000, 4000, 5000, 6000]}
57
+ minMax={[0, 1000, 2000, 3000, 4000, 5000, 6000]}
62
58
  colors={['#4caf50', '#ffeb3b', '#f44336']}
63
59
  title="RPM"
64
60
  />
65
61
  ```
66
62
 
67
- ### Embedded in a custom container (no card)
68
-
69
- ```jsx
70
- <div style={{ width: 200, height: 130 }}>
71
- <HalfGauge
72
- value={55}
73
- ticks={[0, 25, 50, 75, 100]}
74
- colors={['#2196f3', '#e91e63']}
75
- withoutBackground
76
- />
77
- </div>
78
- ```
79
-
80
- ### Custom card size via style prop
81
-
82
- ```jsx
83
- <HalfGauge
84
- value={8}
85
- ticks={[0, 2, 4, 6, 8, 10]}
86
- title="Score"
87
- style={{ width: '12rem', height: '10rem', flexGrow: 0 }}
88
- />
89
- ```
90
-
91
63
  ## Tick behaviour
92
64
 
93
- The `ticks` array defines where major labels appear. Minor ticks are inserted automatically:
65
+ The `minMax` array defines where major labels appear. Minor ticks are inserted automatically:
94
66
 
95
67
  - **≤ 5 major ticks** → 4 minor ticks per gap
96
68
  - **6–16 major ticks** → 2 minor ticks per gap
package/dist/index.cjs.js CHANGED
@@ -14,4 +14,4 @@
14
14
  animation: modern-gauge-fill-tick 1s ease-out forwards;
15
15
  animation-delay: var(--mg-tick-delay, 0s);
16
16
  }
17
- `,document.head.appendChild(o)})();const C=({value:h,colors:a,title:o,minMax:f})=>{const n=f||[0,5,10,15,20],m=n.at(0)??0,Y=n.at(-1)??1,g=h??m,x=y.useRef(`mg-${Math.random().toString(36).substring(2,9)}`).current,p=y.useRef(m);y.useEffect(()=>{const e=setTimeout(()=>{p.current=g},1e3);return()=>clearTimeout(e)},[g]);const j=Y-m||1,b=Math.min(1,Math.max(0,(p.current-m)/j)),v=Math.min(1,Math.max(0,(g-m)/j)),M=Math.PI*40,L=v*M,w=b*M,S=n.length>8;let c=[];if(n.length<17){const e=n.length<6?4:2,i=e+1;for(let r=0;r<n.length;r++)if(c.push({value:n[r],isMajor:!0}),r<n.length-1){const d=n[r],l=(n[r+1]-d)/i;for(let u=1;u<=e;u++)c.push({value:d+u*l,isMajor:!1})}}else c=n.map(e=>({value:e,isMajor:!0}));const I=c.filter(e=>e.isMajor),X=c.map((e,i)=>{const r=c.length-1,s=(i/r*180-180)*(Math.PI/180),l=36,u=e.isMajor?5:2.5,T=I.indexOf(e),F=e.isMajor&&(!S||T%2===0),R=50+l*Math.cos(s),A=45+l*Math.sin(s),E=50+(l-u)*Math.cos(s),G=45+(l-u)*Math.sin(s),k=l-10,P=50+k*Math.cos(s),W=45+k*Math.sin(s);return{value:e.value,innerX:E,innerY:G,outerX:R,outerY:A,labelX:P,labelY:W,showLabel:F}}),$=a&&a.length>=2?a:["#f44336","#9c27b0"];return t.jsx("div",{style:{height:"100%",width:"100%"},children:t.jsxs("div",{style:{width:"100%",height:"100%",position:"relative"},children:[t.jsxs("svg",{width:"100%",height:"100%",viewBox:"0 0 100 55",children:[t.jsx("defs",{children:t.jsx("linearGradient",{id:`gradient-${x}`,gradientUnits:"userSpaceOnUse",x1:10,y1:45,x2:90,y2:45,children:$.map((e,i)=>t.jsx("stop",{offset:`${i/($.length-1)*100}%`,stopColor:e},i))})}),t.jsx("path",{stroke:"#9e9e9e",strokeWidth:"3",strokeLinecap:"round",fill:"none",d:"M 10 45 A 40 40 0 1 1 90 45"}),t.jsx("path",{className:"modern-gauge-arc",fill:"none",strokeWidth:"3",stroke:`url(#gradient-${x})`,strokeLinecap:"round",strokeDashoffset:"0",style:{"--mg-initial-dash":`${w}`,"--mg-final-dash":`${L}`},d:"M 10 45 A 40 40 0 1 1 90 45"}),X.map((e,i)=>{const r=i/(X.length-1),d=r<=v,s=r;return t.jsxs("g",{children:[t.jsx("line",{x1:e.innerX,y1:e.innerY,x2:e.outerX,y2:e.outerY,strokeWidth:"1",strokeLinecap:"round",stroke:"#9e9e9e"}),t.jsx("line",{className:"modern-gauge-tick",x1:e.innerX,y1:e.innerY,x2:e.outerX,y2:e.outerY,strokeWidth:"1",strokeLinecap:"round",style:{"--mg-tick-color":`url(#gradient-${x})`,"--mg-tick-delay":d?`${s}s`:"0s",animationPlayState:d?"running":"paused"}}),e.showLabel&&t.jsx("text",{x:e.labelX,y:e.labelY,textAnchor:"middle",dominantBaseline:"middle",fontSize:"5",fill:"#9e9e9e",fontFamily:"sans-serif",children:e.value})]},e.value)})]}),t.jsxs("div",{style:{position:"absolute",top:"70%",left:"50%",transform:"translate(-50%, -50%)",textAlign:"center",pointerEvents:"none",whiteSpace:"nowrap"},children:[t.jsx("div",{style:{fontSize:"3rem",fontWeight:500,lineHeight:1.2},children:h}),o&&t.jsx("div",{style:{fontSize:"0.9rem",marginTop:"4px"},children:o})]})]},g)})},O=({value:h,colors:a,title:o,minMax:f})=>t.jsx(C,{value:h,colors:a,title:o,minMax:f});exports.HalfGauge=O;
17
+ `,document.head.appendChild(o)})();const W=({value:m,colors:a,title:o,minMax:f})=>{const n=f||[0,5,10,15,20],h=n.at(0)??0,Y=n.at(-1)??1,g=m??h,x=y.useRef(`mg-${Math.random().toString(36).substring(2,9)}`).current,p=y.useRef(h);y.useEffect(()=>{const e=setTimeout(()=>{p.current=g},1e3);return()=>clearTimeout(e)},[g]);const j=Y-h||1,b=Math.min(1,Math.max(0,(p.current-h)/j)),v=Math.min(1,Math.max(0,(g-h)/j)),M=Math.PI*40,L=v*M,w=b*M,S=n.length>8;let c=[];if(n.length<17){const e=n.length<6?4:2,i=e+1;for(let r=0;r<n.length;r++)if(c.push({value:n[r],isMajor:!0}),r<n.length-1){const d=n[r],l=(n[r+1]-d)/i;for(let u=1;u<=e;u++)c.push({value:d+u*l,isMajor:!1})}}else c=n.map(e=>({value:e,isMajor:!0}));const F=c.filter(e=>e.isMajor),X=c.map((e,i)=>{const r=c.length-1,s=(i/r*180-180)*(Math.PI/180),l=36,u=e.isMajor?5:2.5,I=F.indexOf(e),A=e.isMajor&&(!S||I%2===0),R=50+l*Math.cos(s),T=45+l*Math.sin(s),C=50+(l-u)*Math.cos(s),E=45+(l-u)*Math.sin(s),k=l-10,G=50+k*Math.cos(s),P=45+k*Math.sin(s);return{value:e.value,innerX:C,innerY:E,outerX:R,outerY:T,labelX:G,labelY:P,showLabel:A}}),$=a&&a.length>=2?a:["#f44336","#9c27b0"];return t.jsx("div",{style:{height:"100%",width:"100%"},children:t.jsxs("div",{style:{width:"100%",height:"100%",position:"relative"},children:[t.jsxs("svg",{width:"100%",height:"100%",viewBox:"0 0 100 55",children:[t.jsx("defs",{children:t.jsx("linearGradient",{id:`gradient-${x}`,gradientUnits:"userSpaceOnUse",x1:10,y1:45,x2:90,y2:45,children:$.map((e,i)=>t.jsx("stop",{offset:`${i/($.length-1)*100}%`,stopColor:e},i))})}),t.jsx("path",{stroke:"#9e9e9e",strokeWidth:"3",strokeLinecap:"round",fill:"none",d:"M 10 45 A 40 40 0 1 1 90 45"}),t.jsx("path",{className:"modern-gauge-arc",fill:"none",strokeWidth:"3",stroke:`url(#gradient-${x})`,strokeLinecap:"round",strokeDashoffset:"0",style:{"--mg-initial-dash":`${w}`,"--mg-final-dash":`${L}`},d:"M 10 45 A 40 40 0 1 1 90 45"}),X.map((e,i)=>{const r=i/(X.length-1),d=r<=v,s=r;return t.jsxs("g",{children:[t.jsx("line",{x1:e.innerX,y1:e.innerY,x2:e.outerX,y2:e.outerY,strokeWidth:"1",strokeLinecap:"round",stroke:"#9e9e9e"}),t.jsx("line",{className:"modern-gauge-tick",x1:e.innerX,y1:e.innerY,x2:e.outerX,y2:e.outerY,strokeWidth:"1",strokeLinecap:"round",style:{"--mg-tick-color":`url(#gradient-${x})`,"--mg-tick-delay":d?`${s}s`:"0s",animationPlayState:d?"running":"paused"}}),e.showLabel&&t.jsx("text",{x:e.labelX,y:e.labelY,textAnchor:"middle",dominantBaseline:"middle",fontSize:"5",fill:"#9e9e9e",fontFamily:"sans-serif",children:e.value})]},e.value)}),t.jsx("text",{x:50,y:40,textAnchor:"middle",dominantBaseline:"middle",fontSize:"14",fontWeight:"500",fill:"currentColor",fontFamily:"sans-serif",children:m})]}),o&&t.jsx("div",{style:{position:"absolute",bottom:0,width:"100%",textAlign:"center",fontSize:"0.9rem",color:"#9e9e9e",pointerEvents:"none"},children:o})]},g)})},B=({value:m,colors:a,title:o,minMax:f})=>t.jsx(W,{value:m,colors:a,title:o,minMax:f});exports.HalfGauge=B;
package/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
- import { jsx as t, jsxs as f } from "react/jsx-runtime";
2
- import { useRef as j, useEffect as V } from "react";
1
+ import { jsx as t, jsxs as x } from "react/jsx-runtime";
2
+ import { useRef as b, useEffect as R } from "react";
3
3
  (function() {
4
4
  if (typeof document > "u") return;
5
5
  const o = "__modern-half-gauge-styles__";
@@ -23,21 +23,21 @@ import { useRef as j, useEffect as V } from "react";
23
23
  }
24
24
  `, document.head.appendChild(s);
25
25
  })();
26
- const _ = ({ value: m, colors: o, title: s, minMax: p }) => {
27
- const n = p || [0, 5, 10, 15, 20], h = n.at(0) ?? 0, b = n.at(-1) ?? 1, g = m ?? h, y = j(`mg-${Math.random().toString(36).substring(2, 9)}`).current, x = j(h);
28
- V(() => {
26
+ const V = ({ value: m, colors: o, title: s, minMax: f }) => {
27
+ const n = f || [0, 5, 10, 15, 20], h = n.at(0) ?? 0, j = n.at(-1) ?? 1, g = m ?? h, y = b(`mg-${Math.random().toString(36).substring(2, 9)}`).current, p = b(h);
28
+ R(() => {
29
29
  const e = setTimeout(() => {
30
- x.current = g;
30
+ p.current = g;
31
31
  }, 1e3);
32
32
  return () => clearTimeout(e);
33
33
  }, [g]);
34
- const v = b - h || 1, L = Math.min(
34
+ const v = j - h || 1, L = Math.min(
35
35
  1,
36
- Math.max(0, (x.current - h) / v)
36
+ Math.max(0, (p.current - h) / v)
37
37
  ), M = Math.min(
38
38
  1,
39
39
  Math.max(0, (g - h) / v)
40
- ), X = Math.PI * 40, w = M * X, S = L * X, I = n.length > 8;
40
+ ), X = Math.PI * 40, w = M * X, F = L * X, I = n.length > 8;
41
41
  let c = [];
42
42
  if (n.length < 17) {
43
43
  const e = n.length < 6 ? 4 : 2, i = e + 1;
@@ -49,25 +49,25 @@ const _ = ({ value: m, colors: o, title: s, minMax: p }) => {
49
49
  }
50
50
  } else
51
51
  c = n.map((e) => ({ value: e, isMajor: !0 }));
52
- const F = c.filter((e) => e.isMajor), $ = c.map((e, i) => {
53
- const r = c.length - 1, a = (i / r * 180 - 180) * (Math.PI / 180), l = 36, u = e.isMajor ? 5 : 2.5, T = F.indexOf(e), A = e.isMajor && (!I || T % 2 === 0), E = 50 + l * Math.cos(a), W = 45 + l * Math.sin(a), C = 50 + (l - u) * Math.cos(a), G = 45 + (l - u) * Math.sin(a), Y = l - 10, P = 50 + Y * Math.cos(a), R = 45 + Y * Math.sin(a);
52
+ const S = c.filter((e) => e.isMajor), $ = c.map((e, i) => {
53
+ const r = c.length - 1, a = (i / r * 180 - 180) * (Math.PI / 180), l = 36, u = e.isMajor ? 5 : 2.5, A = S.indexOf(e), C = e.isMajor && (!I || A % 2 === 0), E = 50 + l * Math.cos(a), T = 45 + l * Math.sin(a), W = 50 + (l - u) * Math.cos(a), B = 45 + (l - u) * Math.sin(a), Y = l - 10, G = 50 + Y * Math.cos(a), P = 45 + Y * Math.sin(a);
54
54
  return {
55
55
  value: e.value,
56
- innerX: C,
57
- innerY: G,
56
+ innerX: W,
57
+ innerY: B,
58
58
  outerX: E,
59
- outerY: W,
60
- labelX: P,
61
- labelY: R,
62
- showLabel: A
59
+ outerY: T,
60
+ labelX: G,
61
+ labelY: P,
62
+ showLabel: C
63
63
  };
64
64
  }), k = o && o.length >= 2 ? o : ["#f44336", "#9c27b0"];
65
- return /* @__PURE__ */ t("div", { style: { height: "100%", width: "100%" }, children: /* @__PURE__ */ f(
65
+ return /* @__PURE__ */ t("div", { style: { height: "100%", width: "100%" }, children: /* @__PURE__ */ x(
66
66
  "div",
67
67
  {
68
68
  style: { width: "100%", height: "100%", position: "relative" },
69
69
  children: [
70
- /* @__PURE__ */ f("svg", { width: "100%", height: "100%", viewBox: "0 0 100 55", children: [
70
+ /* @__PURE__ */ x("svg", { width: "100%", height: "100%", viewBox: "0 0 100 55", children: [
71
71
  /* @__PURE__ */ t("defs", { children: /* @__PURE__ */ t(
72
72
  "linearGradient",
73
73
  {
@@ -107,7 +107,7 @@ const _ = ({ value: m, colors: o, title: s, minMax: p }) => {
107
107
  strokeLinecap: "round",
108
108
  strokeDashoffset: "0",
109
109
  style: {
110
- "--mg-initial-dash": `${S}`,
110
+ "--mg-initial-dash": `${F}`,
111
111
  "--mg-final-dash": `${w}`
112
112
  },
113
113
  d: "M 10 45 A 40 40 0 1 1 90 45"
@@ -115,7 +115,7 @@ const _ = ({ value: m, colors: o, title: s, minMax: p }) => {
115
115
  ),
116
116
  $.map((e, i) => {
117
117
  const r = i / ($.length - 1), d = r <= M, a = r;
118
- return /* @__PURE__ */ f("g", { children: [
118
+ return /* @__PURE__ */ x("g", { children: [
119
119
  /* @__PURE__ */ t(
120
120
  "line",
121
121
  {
@@ -159,40 +159,42 @@ const _ = ({ value: m, colors: o, title: s, minMax: p }) => {
159
159
  }
160
160
  )
161
161
  ] }, e.value);
162
- })
162
+ }),
163
+ /* @__PURE__ */ t(
164
+ "text",
165
+ {
166
+ x: 50,
167
+ y: 40,
168
+ textAnchor: "middle",
169
+ dominantBaseline: "middle",
170
+ fontSize: "14",
171
+ fontWeight: "500",
172
+ fill: "currentColor",
173
+ fontFamily: "sans-serif",
174
+ children: m
175
+ }
176
+ )
163
177
  ] }),
164
- /* @__PURE__ */ f(
178
+ s && /* @__PURE__ */ t(
165
179
  "div",
166
180
  {
167
181
  style: {
168
182
  position: "absolute",
169
- top: "70%",
170
- left: "50%",
171
- transform: "translate(-50%, -50%)",
183
+ bottom: 0,
184
+ width: "100%",
172
185
  textAlign: "center",
173
- pointerEvents: "none",
174
- whiteSpace: "nowrap"
186
+ fontSize: "0.9rem",
187
+ color: "#9e9e9e",
188
+ pointerEvents: "none"
175
189
  },
176
- children: [
177
- /* @__PURE__ */ t("div", { style: { fontSize: "3rem", fontWeight: 500, lineHeight: 1.2 }, children: m }),
178
- s && /* @__PURE__ */ t(
179
- "div",
180
- {
181
- style: {
182
- fontSize: "0.9rem",
183
- marginTop: "4px"
184
- },
185
- children: s
186
- }
187
- )
188
- ]
190
+ children: s
189
191
  }
190
192
  )
191
193
  ]
192
194
  },
193
195
  g
194
196
  ) });
195
- }, q = ({ value: m, colors: o, title: s, minMax: p }) => /* @__PURE__ */ t(_, { value: m, colors: o, title: s, minMax: p });
197
+ }, q = ({ value: m, colors: o, title: s, minMax: f }) => /* @__PURE__ */ t(V, { value: m, colors: o, title: s, minMax: f });
196
198
  export {
197
199
  q as HalfGauge
198
200
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opstel/modern-gauges",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Animated half-circle gauges React component — zero runtime dependencies",
5
5
  "keywords": [
6
6
  "react",