From bb09648f3d8af6273b3e734d68a4827594337293 Mon Sep 17 00:00:00 2001 From: suraj maurya Date: Fri, 5 Dec 2025 15:22:55 +0530 Subject: [PATCH 01/66] formatting --- README.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 493ac390..b22122a5 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,17 @@ - 🧩 LatestDataWidget +[PyPI](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk)  [Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js) -Displays the latest data from an Anedya node. -Ideal for dashboards that show latest values (like temperature, pressure, humidity, etc.). -πŸš€ Usage Example + +

+ Logo +

+ + +# LatestDataWidget **** + +Displays the latest value of a variable from Anedya. + +## Usage Example ``` import { initAnedyaClient } from "../utils/anedyaClient"; @@ -224,12 +232,12 @@ Example returning multiple overrides: ``` - 🧩 Latest Data Guage +# Latest Data Guage ** ** -Displays the latest sensor or node data from an Anedya network node in a guage +Displays the latest variable's data from an Anedya node in a guage -πŸš€ Usage Example +Usage Example ```import { initAnedyaClient } from "../utils/anedyaClient"; import { LatestDataGauge } from "../components/LatestDataWidget"; @@ -341,12 +349,12 @@ Example returning multiple overrides: ``` -🧩 Chart Widget +# Chart Widget **** Displays the historical time-series data for a given variable in chart form -πŸš€ Usage Example +Usage Example ```import { initAnedyaClient } from "../utils/anedyaClient"; import { ChartWidget } from "../components/LatestDataWidget"; From 3488b0004397e868c5725e8fb012371b2dc9b99e Mon Sep 17 00:00:00 2001 From: suraj maurya Date: Fri, 5 Dec 2025 15:26:36 +0530 Subject: [PATCH 02/66] or --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b22122a5..d0519bea 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

-# LatestDataWidget **** +# LatestDataWidget `````` Displays the latest value of a variable from Anedya. @@ -232,7 +232,7 @@ Example returning multiple overrides: ``` -# Latest Data Guage ** ** +# Latest Data Guage ``` ``` Displays the latest variable's data from an Anedya node in a guage @@ -349,7 +349,7 @@ Example returning multiple overrides: ``` -# Chart Widget **** +# Chart Widget `````` Displays the historical time-series data for a given variable in chart form From ef15a8dc15dd54cbc90dcf651bdb20c067e1a39a Mon Sep 17 00:00:00 2001 From: suraj maurya Date: Fri, 5 Dec 2025 15:30:08 +0530 Subject: [PATCH 03/66] formate example readme --- examples/README.md | 44 +------------------------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/examples/README.md b/examples/README.md index 022fde3e..d7f56139 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,4 +1,4 @@ -# Anedya Public SDK β€” README +# Anedya Public SDK β€” Getting Started ## Overview @@ -43,48 +43,6 @@ Use the documentation here: 2. Navigate to **Access Tokens**. 3. Create a token using the UI. -### Token Body (Dashboard) - -Below is the JSON body you will submit when creating a token through the dashboard: - -```json -{ - "resources": { - "nodes": [ - "----ADD YOUR NODES HERE---" - ], - "variables": [ - "----ADD YOUR VARIABLES HERE---" - ], - "vsglobalscopes": [ - "------ ADD YOUR Namespace HERE----" - ], - "vskeys": [ - "----- ADD YOUR KEY -----" - ], - "streams": [ - "----- ADD STREAMS HERE ----" - ] - }, - "allow": [ - "data::getsnapshot", - "data::getlatest", - "data::gethistorical", - "cmd::sendcommand", - "cmd::listcommands", - "cmd::getstatus", - "cmd::invalidate", - "vs::getvalue", - "vs::setvalue", - "vs::scankeys", - "vs::deletekeys", - "streams::connect", - "health::gethbstats", - "health::getstatus" - ] -} -``` - ### Important Once your **token** and **tokenId** are created: From 7d305df50b2fd00d8bd47ae8a18e165429c0ce78 Mon Sep 17 00:00:00 2001 From: suraj maurya Date: Fri, 5 Dec 2025 15:38:19 +0530 Subject: [PATCH 04/66] or --- README.md | 18 +++++++++--------- examples/README.md | 14 +++----------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d0519bea..71c2f78c 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ Displays the latest value of a variable from Anedya. ## Usage Example ``` -import { initAnedyaClient } from "../utils/anedyaClient"; +import { anedyaClientInit } from "../utils/anedyaClient"; import { LatestDataWidget } from "../components/LatestDataWidget"; -const client = initAnedyaClient("TOKEN_ID", "TOKEN"); +const client = anedyaClientInit("TOKEN_ID", "TOKEN"); function App() { return ( @@ -45,7 +45,7 @@ value: { fontWeight: 800 }, | **Prop** | **Type** | **Required** | **Description** | |--------------------|-------------------------------------------------|:------------:|----------------------------------------------------------------------------| -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using initAnedyaClient(). | +| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | | nodeId | string | βœ… | ID of the node whose latest data is to be fetched | | variable | string | βœ… | The variable name (key) to fetch from the node’s data. | | title | string | ❌ | Optional label displayed above the value. | @@ -239,10 +239,10 @@ Displays the latest variable's data from an Anedya node in a guage Usage Example -```import { initAnedyaClient } from "../utils/anedyaClient"; +```import { anedyaClientInit } from "../utils/anedyaClient"; import { LatestDataGauge } from "../components/LatestDataWidget"; -const client = initAnedyaClient("TOKEN_ID", "TOKEN"); +const client = anedyaClientInit("TOKEN_ID", "TOKEN"); function App() { return ( @@ -288,7 +288,7 @@ return ( | **Prop** | **Type** | **Required** | **Description** | |--------------------|-------------------------------------------------|:------------:|----------------------------------------------------------------------------| -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using initAnedyaClient(). | +| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | | nodeId | string | βœ… | ID of the node whose latest data is to be fetched | | variable | string | βœ… | The variable name (key) to fetch from the node’s data. | | title | string | ❌ | Optional label displayed above the value. | @@ -356,10 +356,10 @@ Displays the historical time-series data for a given variable in chart form Usage Example -```import { initAnedyaClient } from "../utils/anedyaClient"; +```import { anedyaClientInit } from "../utils/anedyaClient"; import { ChartWidget } from "../components/LatestDataWidget"; -const client = initAnedyaClient("TOKEN_ID", "TOKEN"); +const client = anedyaClientInit("TOKEN_ID", "TOKEN"); function App() { return ( @@ -414,7 +414,7 @@ return ( | **Prop** | **Type** | **Required** | **Description** | |--------------------|-------------------------------------------------|:------------:|----------------------------------------------------------------------------| -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using initAnedyaClient(). | +| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | | nodeId | string | βœ… | ID of the node whose latest data is to be fetched | | variable | string | βœ… | The variable name (key) to fetch from the node’s data. | from | number | βœ… | earliest timestamp or date from which data should be fetched, in milliseconds epoch diff --git a/examples/README.md b/examples/README.md index d7f56139..139b7ad2 100644 --- a/examples/README.md +++ b/examples/README.md @@ -31,14 +31,6 @@ To send (ingest) data into Anedya: To use the SDK, you must generate an access token. There are two ways: -### **Option A: Create via Platform API** - -Use the documentation here: - -* [https://docs.anedya.io/platform-api/access-token-create/](https://docs.anedya.io/platform-api/access-token-create/) - -### **Option B: Create via Anedya Dashboard** - 1. Go to your project dashboard. 2. Navigate to **Access Tokens**. 3. Create a token using the UI. @@ -65,7 +57,7 @@ npm install public-sdk ## 4. Import the SDK Components ```javascript -import initAnedyaClient, { LatestDataComponent, ChartWidget, LatestDataGauge } from "public-sdk"; +import anedyaClientInit, { LatestDataComponent, ChartWidget, LatestDataGauge } from "public-sdk"; ``` --- @@ -73,7 +65,7 @@ import initAnedyaClient, { LatestDataComponent, ChartWidget, LatestDataGauge } f ## 5. Initialize the Anedya Client ```javascript -const client = initAnedyaClient(tokenId, token); +const client = anedyaClientInit(tokenId, token); ``` --- @@ -126,7 +118,7 @@ function App() { const nodeId = ""; const tokenId = ""; const token = ""; - const client = initAnedyaClient(tokenId, token); + const client = anedyaClientInit(tokenId, token); const currentTime = Date.now(); // ms timestamp From 7f3181382e730815eacfd07451a2f682328deae6 Mon Sep 17 00:00:00 2001 From: suraj maurya Date: Fri, 5 Dec 2025 15:39:53 +0530 Subject: [PATCH 05/66] add desc --- README.md | 168 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 94 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 71c2f78c..9f576333 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,20 @@ [PyPI](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk)  [Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js) -

Logo

-# LatestDataWidget `````` +The Anedya Public SDK helps you easily fetch data from Anedya and display it using prebuilt, customizable React widget components. These widgets allow you to quickly visualize IoT data such as latest values and timeseries data. + +This SDK currently provides: + +- **LatestDataComponent** β€” Displays the latest value of a variable. +- **ChartWidget** β€” Displays timeseries data between given timestamps. +- **LatestDataGauge** β€” A gauge‑style visualization of the latest value. + +# LatestDataWidget `` Displays the latest value of a variable from Anedya. @@ -44,16 +51,16 @@ value: { fontWeight: 800 }, βš™οΈ Props | **Prop** | **Type** | **Required** | **Description** | -|--------------------|-------------------------------------------------|:------------:|----------------------------------------------------------------------------| -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | -| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | -| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | -| title | string | ❌ | Optional label displayed above the value. | -| unit | string | ❌ | Unit of measurement shown after the value. | -| styles | StyleSet | ❌ | Custom style overrides for container, label, value, and unit. | -| colorRange | typeof defaultColorRanges | ❌ | Optional custom color range configuration. | -| colorRangeCallback | (value: number, defaultColor: string) => string | ❌ | Callback that lets you overrride the computed color logic for data values. | -| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | +| ------------------ | ----------------------------------------------- | :----------: | -------------------------------------------------------------------------- | +| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | +| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | +| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | +| title | string | ❌ | Optional label displayed above the value. | +| unit | string | ❌ | Unit of measurement shown after the value. | +| styles | StyleSet | ❌ | Custom style overrides for container, label, value, and unit. | +| colorRange | typeof defaultColorRanges | ❌ | Optional custom color range configuration. | +| colorRangeCallback | (value: number, defaultColor: string) => string | ❌ | Callback that lets you overrride the computed color logic for data values. | +| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | 🎨 Styling @@ -132,7 +139,7 @@ The displayText callback lets you customize: - what unit text should look like -- here the unit is placed +- here the unit is placed - unit formatting style (normal, subscript, superscript) @@ -148,28 +155,30 @@ displayText?: (value: number, unit: string) => { ``` ### Usage Example - ``` - ({ - text: `${value}`, - unitText: unit, - position: "right", // left | right | top | bottom - unitStyle: "normal", // normal | subscript | superscript - })} + +``` + ({ + text: `${value}`, + unitText: unit, + position: "right", // left | right | top | bottom + unitStyle: "normal", // normal | subscript | superscript + })} /> ``` -| Property | Type |Description | +| Property | Type | Description | | ------------- | ------------------------------------------ | ----------------------------------------------------- | | **text** | `string` | The formatted value to display | | **unitText** | `string` | Custom unit text (optional) | | **position** | `"left" \| "right" \| "top" \| "bottom"` | Where the unit should be placed relative to the value | | **unitStyle** | `"normal" \| "subscript" \| "superscript"` | Choose how the unit should appear | - ### Examples + #### Move unit to the top + ``` displayText={() => ({ text: "25.3", unitText: "Β°C", position: "top" })} ``` @@ -183,17 +192,19 @@ displayText={(value) => ({ unitStyle: "subscript", })} ``` + ## 2. onStyleChange Callback (Dynamic Styling) This callback lets you override widget styling based on live value updates. It receives the current numeric value and should return partial styles, which will override the base styles. -### What This Callback Looks Like +### What This Callback Looks Like ``` onStyleChange?: (value: number) => Partial; ``` + ### Usage Example ``` @@ -211,6 +222,7 @@ onStyleChange?: (value: number) => Partial; }} /> ``` + ### What you can style dynamically You may return overrides for: @@ -224,19 +236,18 @@ You may return overrides for: | `fontFamily` | Override global font family | Example returning multiple overrides: - ``` - return { - container: { background: "#ffeeee" }, - value: { color: "#d60000", fontSize: "90px" }, + +``` +return { + container: { background: "#ffeeee" }, + value: { color: "#d60000", fontSize: "90px" }, }; ``` - -# Latest Data Guage ``` ``` +# Latest Data Guage `` Displays the latest variable's data from an Anedya node in a guage - Usage Example ```import { anedyaClientInit } from "../utils/anedyaClient"; @@ -252,7 +263,7 @@ return ( variable="temperature" title="Temperature Sensor" unit={"Β°C"} - + showNeedle={false} styles={{ container: { @@ -286,17 +297,16 @@ return ( βš™οΈ Props -| **Prop** | **Type** | **Required** | **Description** | -|--------------------|-------------------------------------------------|:------------:|----------------------------------------------------------------------------| -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | -| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | -| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | -| title | string | ❌ | Optional label displayed above the value. | -| unit | string | ❌ | Unit of measurement shown after the value. | -| styles | StyleSet | ❌ | Custom style overrides for container, label, value, and unit. | -| colorRange | typeof defaultColorRanges | ❌ | Optional custom color range configuration. | -| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | - +| **Prop** | **Type** | **Required** | **Description** | +| ---------- | ------------------------- | :----------: | ------------------------------------------------------------------------ | +| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | +| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | +| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | +| title | string | ❌ | Optional label displayed above the value. | +| unit | string | ❌ | Unit of measurement shown after the value. | +| styles | StyleSet | ❌ | Custom style overrides for container, label, value, and unit. | +| colorRange | typeof defaultColorRanges | ❌ | Optional custom color range configuration. | +| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | πŸ“Œ Latest Data Gauge Widget β€” Callback Options @@ -306,11 +316,12 @@ This callback lets you override widget styling based on live value updates. It receives the current numeric value and should return partial styles, which will override the base styles. -### What This Callback Looks Like +### What This Callback Looks Like ``` onStyleChange?: (value: number) => Partial; ``` + ### Usage Example ``` @@ -328,6 +339,7 @@ onStyleChange?: (value: number) => Partial; }} /> ``` + ### What you can style dynamically You may return overrides for: @@ -341,19 +353,18 @@ You may return overrides for: | `fontFamily` | Override global font family | Example returning multiple overrides: - ``` - return { - container: { background: "#ffeeee" }, - value: { color: "#d60000", fontSize: "90px" }, + +``` +return { + container: { background: "#ffeeee" }, + value: { color: "#d60000", fontSize: "90px" }, }; ``` - -# Chart Widget `````` +# Chart Widget `` Displays the historical time-series data for a given variable in chart form - Usage Example ```import { anedyaClientInit } from "../utils/anedyaClient"; @@ -412,18 +423,18 @@ return ( βš™οΈ Props -| **Prop** | **Type** | **Required** | **Description** | -|--------------------|-------------------------------------------------|:------------:|----------------------------------------------------------------------------| -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | -| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | -| variable | string | βœ… | The variable name (key) to fetch from the node’s data. -| from | number | βœ… | earliest timestamp or date from which data should be fetched, in milliseconds epoch -| to | number | βœ… | latest timestamp or date from which data should be fetched, in milliseconds epoch -| title | string | ❌ | Optional label displayed above the value. -| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). -| tickCount | number | ❌ | # of X-axis ticks -| tooltipFormatter | `(p)=>string` | ❌ | Tooltip HTML (p is timestamp in seconds epoch) -| styles | StyleSet | ❌ | Custom style overrides for container +| **Prop** | **Type** | **Required** | **Description** | +| ---------------- | ------------- | :----------: | ----------------------------------------------------------------------------------- | +| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | +| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | +| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | +| from | number | βœ… | earliest timestamp or date from which data should be fetched, in milliseconds epoch | +| to | number | βœ… | latest timestamp or date from which data should be fetched, in milliseconds epoch | +| title | string | ❌ | Optional label displayed above the value. | +| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | +| tickCount | number | ❌ | # of X-axis ticks | +| tooltipFormatter | `(p)=>string` | ❌ | Tooltip HTML (p is timestamp in seconds epoch) | +| styles | StyleSet | ❌ | Custom style overrides for container | πŸ“Š Chart Widget β€” Callback Options @@ -441,7 +452,8 @@ xTickFormat?: (value: number | Date | string) => string; ``` ### Example - ``` + +``` xTickFormat={(d) => d.toLocaleDateString()} ``` @@ -454,19 +466,20 @@ xTickFormat={(d) => d.toLocaleDateString()} - Apply locale-based formats - ## 2. yTickFormat (Format Y-Axis Labels) Use this to format numeric Y-axis values. -### What This Callback Looks Like +### What This Callback Looks Like ``` yTickFormat?: (value: number) => string; ``` + ### Example - ``` + +``` yTickFormat={(v) => `${v} Β°C`} ``` @@ -483,23 +496,26 @@ yTickFormat={(v) => `${v} Β°C`} This callback returns the content string used in tooltips when hovering on data points. -### What This Callback Looks Like +### What This Callback Looks Like -``` +``` tooltipFormat?: (dataPoint: ChartDataPoint, unit: string) => string; ``` + Where ChartDataPoint is typically: -``` +``` { timestamp: number; value: number; } ``` + ### Example - ``` + +``` tooltipFormat={(d, unit) => - `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` + `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` } ``` @@ -512,12 +528,15 @@ tooltipFormat={(d, unit) => - Show multi-line tooltip content ## 4. onStyleChange (Dynamic Chart Styling) + This callback allows dynamic runtime style overrides based on the current chart data. ### What This Callback Looks Like + ``` onStyleChange?: (data: ChartDataPoint[]) => Partial; ``` + You can return overrides for any part of the chart: | Key | Description | @@ -544,10 +563,11 @@ onStyleChange={(data) => { ``` ### Use cases + - Highlight chart when values exceed thresholds - Change themes based on the data - Dim colors when dataset is small -- Respond to live-updating data streams \ No newline at end of file +- Respond to live-updating data streams From 52d99e6a669c12bdda64bf86b447a0f20d46b890 Mon Sep 17 00:00:00 2001 From: suraj maurya Date: Fri, 5 Dec 2025 15:42:21 +0530 Subject: [PATCH 06/66] add links --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9f576333..c61607ec 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ The Anedya Public SDK helps you easily fetch data from Anedya and display it usi This SDK currently provides: -- **LatestDataComponent** β€” Displays the latest value of a variable. -- **ChartWidget** β€” Displays timeseries data between given timestamps. -- **LatestDataGauge** β€” A gauge‑style visualization of the latest value. +- [**LatestDataComponent**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latestdatawidget-latestdatawidget) β€” Displays the latest value of a variable. +- [**ChartWidget**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latest-data-guage-latestdatagauge-) β€” Displays timeseries data between given timestamps. +- [**LatestDataGauge**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#chart-widget-chartwidget-) β€” A gauge‑style visualization of the latest value. # LatestDataWidget `` From d3a34bbe9fb66f0fa6557c0eb9fee4985cb149eb Mon Sep 17 00:00:00 2001 From: abhishreecodes <156026573+abhishreecodes@users.noreply.github.com> Date: Fri, 5 Dec 2025 15:56:55 +0530 Subject: [PATCH 07/66] Update README.md --- examples/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/README.md b/examples/README.md index 139b7ad2..2e922ca5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,7 +6,7 @@ The Anedya Public SDK helps you easily fetch data from Anedya and display it usi This SDK currently provides: -* **LatestDataComponent** β€” Displays the latest value of a variable. +* **LatestDataWidget** β€” Displays the latest value of a variable. * **ChartWidget** β€” Displays timeseries data between given timestamps. * **LatestDataGauge** β€” A gauge‑style visualization of the latest value. @@ -57,7 +57,7 @@ npm install public-sdk ## 4. Import the SDK Components ```javascript -import anedyaClientInit, { LatestDataComponent, ChartWidget, LatestDataGauge } from "public-sdk"; +import anedyaClientInit, { LatestDataWidget, ChartWidget, LatestDataGauge } from "public-sdk"; ``` --- @@ -142,16 +142,16 @@ const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp /> - {/* Latest Data Component */} + {/* Latest Data Widget */}
-
- {/* Gauge Component */} + {/* Gauge Widget */}
Date: Fri, 5 Dec 2025 16:00:04 +0530 Subject: [PATCH 08/66] Update README.md --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c61607ec..6a0ff65b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The Anedya Public SDK helps you easily fetch data from Anedya and display it usi This SDK currently provides: -- [**LatestDataComponent**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latestdatawidget-latestdatawidget) β€” Displays the latest value of a variable. +- [**LatestDataWidget**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latestdatawidget-latestdatawidget) β€” Displays the latest value of a variable. - [**ChartWidget**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latest-data-guage-latestdatagauge-) β€” Displays timeseries data between given timestamps. - [**LatestDataGauge**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#chart-widget-chartwidget-) β€” A gauge‑style visualization of the latest value. @@ -157,7 +157,7 @@ displayText?: (value: number, unit: string) => { ### Usage Example ``` - ({ text: `${value}`, @@ -208,7 +208,7 @@ onStyleChange?: (value: number) => Partial; ### Usage Example ``` - { if (value > 80) { @@ -246,7 +246,7 @@ return { # Latest Data Guage `` -Displays the latest variable's data from an Anedya node in a guage +Displays a variable's latest data from an Anedya node in a guage Usage Example @@ -263,8 +263,6 @@ return ( variable="temperature" title="Temperature Sensor" unit={"Β°C"} - - showNeedle={false} styles={{ container: { width: 350, From e2c922893e83bde3a0be66ff534e21a56b710007 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 31 Mar 2026 18:14:52 +0530 Subject: [PATCH 09/66] commit --- src/components/ChartWidget.tsx | 2 +- src/components/StreamWidgets.tsx | 73 + test/my-app/.gitignore | 24 + test/my-app/README.md | 18 + test/my-app/eslint.config.js | 29 + test/my-app/index.html | 13 + test/my-app/package-lock.json | 2633 ++++++++++++++++++++++++++++++ test/my-app/package.json | 30 + test/my-app/public/favicon.svg | 1 + test/my-app/public/icons.svg | 24 + test/my-app/src/App.css | 184 +++ test/my-app/src/App.jsx | 203 +++ test/my-app/src/assets/hero.png | Bin 0 -> 44919 bytes test/my-app/src/assets/react.svg | 1 + test/my-app/src/assets/vite.svg | 1 + test/my-app/src/index.css | 111 ++ test/my-app/src/main.jsx | 10 + test/my-app/vite.config.js | 11 + 18 files changed, 3367 insertions(+), 1 deletion(-) create mode 100644 src/components/StreamWidgets.tsx create mode 100644 test/my-app/.gitignore create mode 100644 test/my-app/README.md create mode 100644 test/my-app/eslint.config.js create mode 100644 test/my-app/index.html create mode 100644 test/my-app/package-lock.json create mode 100644 test/my-app/package.json create mode 100644 test/my-app/public/favicon.svg create mode 100644 test/my-app/public/icons.svg create mode 100644 test/my-app/src/App.css create mode 100644 test/my-app/src/App.jsx create mode 100644 test/my-app/src/assets/hero.png create mode 100644 test/my-app/src/assets/react.svg create mode 100644 test/my-app/src/assets/vite.svg create mode 100644 test/my-app/src/index.css create mode 100644 test/my-app/src/main.jsx create mode 100644 test/my-app/vite.config.js diff --git a/src/components/ChartWidget.tsx b/src/components/ChartWidget.tsx index d0d644b0..551ca540 100644 --- a/src/components/ChartWidget.tsx +++ b/src/components/ChartWidget.tsx @@ -3,7 +3,7 @@ import * as d3 from "d3"; import { CSSProperties } from "react"; -import "../../src/index.css" +// import "../../src/index.css" import { validateRequiredProps } from "../helpers/validate"; import { defaultDateFormatter, formatDate, formatNumber } from "../helpers/formatDate"; diff --git a/src/components/StreamWidgets.tsx b/src/components/StreamWidgets.tsx new file mode 100644 index 00000000..f678913c --- /dev/null +++ b/src/components/StreamWidgets.tsx @@ -0,0 +1,73 @@ +// StreamWidget.tsx +import React, { useEffect, useRef } from "react"; +import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; +import { validateRequiredProps } from "../helpers/validate"; + +export interface StreamWidgetProps { + client: any; + nodeId: string; + streamId: string; + streamUrl: string; +} + +export const StreamWidget: React.FC = ({ + client, + nodeId, + streamId, + streamUrl, +}) => { + validateRequiredProps("StreamWidget", { client, nodeId, streamId, streamUrl }, [ + "client", + "nodeId", + "streamId", + "streamUrl", + ]); + + const mountedRef = useRef(false); + + useEffect(() => { + if (!client || !nodeId || !streamId || !streamUrl) return; + mountedRef.current = true; + + const anedya = (client as any)._anedya as Anedya; + + const node = anedya.NewNode(client, nodeId); + console.log("Stream Node : ", node); + console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(node))); + + const stream = node.getStream(streamId, streamUrl); + + stream.onData((data: any) => { + if (!mountedRef.current) return; + console.log("Stream Data:", data); + }); + + stream.onError((err: any) => { + if (!mountedRef.current) return; + console.error("Stream Error:", err); + }); + + stream + .connect() + .then(() => { + if (mountedRef.current) console.log("Stream connected"); + }) + .catch((err: any) => { + console.error("Stream connect failed:", err); + }); + + return () => { + mountedRef.current = false; + stream.disconnect(); + console.log("Stream disconnected"); + }; + }, [client, nodeId, streamId, streamUrl]); + + return( + <> +

Stream

+ + ); +}; + +export default StreamWidget; \ No newline at end of file diff --git a/test/my-app/.gitignore b/test/my-app/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/test/my-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/test/my-app/README.md b/test/my-app/README.md new file mode 100644 index 00000000..e16d995e --- /dev/null +++ b/test/my-app/README.md @@ -0,0 +1,18 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. + +Note: This will impact Vite dev & build performances. + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/test/my-app/eslint.config.js b/test/my-app/eslint.config.js new file mode 100644 index 00000000..4fa125da --- /dev/null +++ b/test/my-app/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/test/my-app/index.html b/test/my-app/index.html new file mode 100644 index 00000000..e8c3f2af --- /dev/null +++ b/test/my-app/index.html @@ -0,0 +1,13 @@ + + + + + + + Anedya Widgets SDK + + +
+ + + diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json new file mode 100644 index 00000000..34023821 --- /dev/null +++ b/test/my-app/package-lock.json @@ -0,0 +1,2633 @@ +{ + "name": "my-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "my-app", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@babel/core": "^7.29.0", + "@eslint/js": "^9.39.4", + "@rolldown/plugin-babel": "^0.2.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "babel-plugin-react-compiler": "^1.0.0", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", + "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.122.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", + "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", + "integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz", + "integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz", + "integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz", + "integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz", + "integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz", + "integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz", + "integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz", + "integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz", + "integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz", + "integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz", + "integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/plugin-babel": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.2.tgz", + "integrity": "sha512-q9pE8+47bQNHb5eWVcE6oXppA+JTSwvnrhH53m0ZuHuK5MLvwsLoWrWzBTFQqQ06BVxz1gp0HblLsch8o6pvZw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=22.12.0 || ^24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.29.0 || ^8.0.0-rc.1", + "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", + "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", + "rolldown": "^1.0.0-rc.5", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@babel/plugin-transform-runtime": { + "optional": true + }, + "@babel/runtime": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", + "integrity": "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001782", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz", + "integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.329", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz", + "integrity": "sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", + "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.122.0", + "@rolldown/pluginutils": "1.0.0-rc.12" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.12", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", + "@rolldown/binding-darwin-x64": "1.0.0-rc.12", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz", + "integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.3.tgz", + "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.12", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/test/my-app/package.json b/test/my-app/package.json new file mode 100644 index 00000000..1df23585 --- /dev/null +++ b/test/my-app/package.json @@ -0,0 +1,30 @@ +{ + "name": "my-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@babel/core": "^7.29.0", + "@eslint/js": "^9.39.4", + "@rolldown/plugin-babel": "^0.2.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "babel-plugin-react-compiler": "^1.0.0", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } +} diff --git a/test/my-app/public/favicon.svg b/test/my-app/public/favicon.svg new file mode 100644 index 00000000..6893eb13 --- /dev/null +++ b/test/my-app/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/my-app/public/icons.svg b/test/my-app/public/icons.svg new file mode 100644 index 00000000..e9522193 --- /dev/null +++ b/test/my-app/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/my-app/src/App.css b/test/my-app/src/App.css new file mode 100644 index 00000000..f90339d8 --- /dev/null +++ b/test/my-app/src/App.css @@ -0,0 +1,184 @@ +.counter { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--accent); + background: var(--accent-bg); + border: 2px solid transparent; + transition: border-color 0.3s; + margin-bottom: 24px; + + &:hover { + border-color: var(--accent-border); + } + &:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) + scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) + scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + & > div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx new file mode 100644 index 00000000..54e710e8 --- /dev/null +++ b/test/my-app/src/App.jsx @@ -0,0 +1,203 @@ +import React from "react"; +import { + LatestDataWidget, + anedyaClientInit, + ChartWidget, + LatestDataGauge, + StreamWidget +} from "public-widget-sdk"; + +// import {StreamWidget} from "public-widget-sdk" + +function App() { + + const tokenId = "itATCNCVamYNmwfdeBumQMwS"; + const token = "Evd8wL35Xt4tNQOXP11YddiRHtM74jqw3JZYuIaPmnWxNozbmnNTUfVaqXmQERV1"; + const nodeId = "20deeee8-f8ae-11ee-9dd8-c3aa61afe2fb"; + const client = anedyaClientInit(tokenId, token); + + console.log(client, "client"); + + const currentTime = Date.now(); // ms timestamp + const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp + + return ( +
+

Test Widget SDK

+
+
+ d.toLocaleDateString()} + yTickFormat={(v) => `${v} Β°C`} + tooltipFormat={(d, unit) => + `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` + } + onStyleChange={(data) => { + return { + title: { color: "red" }, + container: { + background: "rgba(232, 236, 240, 1)", + borderRadius: 10, + }, + }; + }} + /> +
+ +
+ { + return { + text: `${value}`, + unitText: unit, + position: "right", // "left" | "right" | "top" | "bottom" + unitStyle: "subscript", // "normal" | "subscript" | "superscript" + }; + }} + onStyleChange={(value) => { + if (value > 80) { + return { + value: { color: "black" }, + label: { color: "orange" }, + }; + } + + return {}; // keep original styling + }} + /> +
+ +
+ { + if (value > 80) { + return { + value: { color: "red" }, + label: { color: "orange" }, + }; + } + + return {}; // keep original styling + }} + /> +
+ +
+ +
+
+
+ ); +} + +export default App; diff --git a/test/my-app/src/assets/hero.png b/test/my-app/src/assets/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..cc51a3d20ad4bc961b596a6adfd686685cd84bb0 GIT binary patch literal 44919 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 JPDHLkV1myZcL)Fg literal 0 HcmV?d00001 diff --git a/test/my-app/src/assets/react.svg b/test/my-app/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/test/my-app/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/my-app/src/assets/vite.svg b/test/my-app/src/assets/vite.svg new file mode 100644 index 00000000..5101b674 --- /dev/null +++ b/test/my-app/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/test/my-app/src/index.css b/test/my-app/src/index.css new file mode 100644 index 00000000..2c84af06 --- /dev/null +++ b/test/my-app/src/index.css @@ -0,0 +1,111 @@ +:root { + --text: #6b6375; + --text-h: #08060d; + --bg: #fff; + --border: #e5e4e7; + --code-bg: #f4f3ec; + --accent: #aa3bff; + --accent-bg: rgba(170, 59, 255, 0.1); + --accent-border: rgba(170, 59, 255, 0.5); + --social-bg: rgba(244, 243, 236, 0.5); + --shadow: + rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; + + --sans: system-ui, 'Segoe UI', Roboto, sans-serif; + --heading: system-ui, 'Segoe UI', Roboto, sans-serif; + --mono: ui-monospace, Consolas, monospace; + + font: 18px/145% var(--sans); + letter-spacing: 0.18px; + color-scheme: light dark; + color: var(--text); + background: var(--bg); + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + @media (max-width: 1024px) { + font-size: 16px; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --text: #9ca3af; + --text-h: #f3f4f6; + --bg: #16171d; + --border: #2e303a; + --code-bg: #1f2028; + --accent: #c084fc; + --accent-bg: rgba(192, 132, 252, 0.15); + --accent-border: rgba(192, 132, 252, 0.5); + --social-bg: rgba(47, 48, 58, 0.5); + --shadow: + rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; + } + + #social .button-icon { + filter: invert(1) brightness(2); + } +} + +body { + margin: 0; +} + +#root { + width: 1126px; + max-width: 100%; + margin: 0 auto; + text-align: center; + border-inline: 1px solid var(--border); + min-height: 100svh; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +h1, +h2 { + font-family: var(--heading); + font-weight: 500; + color: var(--text-h); +} + +h1 { + font-size: 56px; + letter-spacing: -1.68px; + margin: 32px 0; + @media (max-width: 1024px) { + font-size: 36px; + margin: 20px 0; + } +} +h2 { + font-size: 24px; + line-height: 118%; + letter-spacing: -0.24px; + margin: 0 0 8px; + @media (max-width: 1024px) { + font-size: 20px; + } +} +p { + margin: 0; +} + +code, +.counter { + font-family: var(--mono); + display: inline-flex; + border-radius: 4px; + color: var(--text-h); +} + +code { + font-size: 15px; + line-height: 135%; + padding: 4px 8px; + background: var(--code-bg); +} diff --git a/test/my-app/src/main.jsx b/test/my-app/src/main.jsx new file mode 100644 index 00000000..b9a1a6de --- /dev/null +++ b/test/my-app/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/test/my-app/vite.config.js b/test/my-app/vite.config.js new file mode 100644 index 00000000..d1203cd0 --- /dev/null +++ b/test/my-app/vite.config.js @@ -0,0 +1,11 @@ +import { defineConfig } from 'vite' +import react, { reactCompilerPreset } from '@vitejs/plugin-react' +import babel from '@rolldown/plugin-babel' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react(), + babel({ presets: [reactCompilerPreset()] }) + ], +}) From 8d69d3e30c90279f5e002330211536319954b2a5 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 14 Jul 2026 11:26:14 +0530 Subject: [PATCH 10/66] commit --- package-lock.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package-lock.json b/package-lock.json index 2d81a607..90ab968c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -290,6 +290,7 @@ "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.0.2" } @@ -637,6 +638,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } From 94cd7f0e9c0da65a2d1bad22194b3b230e218ea6 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 14 Jul 2026 11:27:22 +0530 Subject: [PATCH 11/66] remove credentials --- test/my-app/src/App.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 54e710e8..b4e21112 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -11,9 +11,9 @@ import { function App() { - const tokenId = "itATCNCVamYNmwfdeBumQMwS"; - const token = "Evd8wL35Xt4tNQOXP11YddiRHtM74jqw3JZYuIaPmnWxNozbmnNTUfVaqXmQERV1"; - const nodeId = "20deeee8-f8ae-11ee-9dd8-c3aa61afe2fb"; + const tokenId = ""; + const token = ""; + const nodeId = ""; const client = anedyaClientInit(tokenId, token); console.log(client, "client"); From 3cf0c8ed155266c24aa8dbcac65516d7625168a4 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Tue, 14 Jul 2026 16:29:36 +0530 Subject: [PATCH 12/66] added chart widget and chart theme --- dist/styles.css | 2 + examples/application-example.js | 6 +- package-lock.json | 4314 ++++++++++++++++++++++++---- package.json | 34 +- public-widget-sdk@5.5.0 | 0 rollup | 0 src/components/ChartWidget.tsx | 1055 +++---- src/components/LatestDataGauge.tsx | 40 + src/components/chartTheme.tsx | 222 ++ src/hooks/AnedyaFrontendClient.ts | 8 +- src/hooks/Older.ts | 4 +- src/index.css | 2 + src/index.ts | 1 + src/styles.css | 1 + tailwind.config.js | 0 test/my-app/.gitignore | 24 + test/my-app/README.md | 18 + test/my-app/eslint.config.js | 29 + test/my-app/index.html | 13 + test/my-app/package-lock.json | 2648 +++++++++++++++++ test/my-app/package.json | 30 + test/my-app/public/favicon.svg | 1 + test/my-app/public/icons.svg | 24 + test/my-app/src/App.css | 184 ++ test/my-app/src/App.jsx | 157 + test/my-app/src/assets/hero.png | Bin 0 -> 44919 bytes test/my-app/src/assets/react.svg | 1 + test/my-app/src/assets/vite.svg | 1 + test/my-app/src/index.css | 111 + test/my-app/src/main.jsx | 10 + test/my-app/vite.config.js | 15 + ts.config.json | 16 + tsup.config.ts | 9 + 33 files changed, 7798 insertions(+), 1182 deletions(-) create mode 100644 dist/styles.css create mode 100644 public-widget-sdk@5.5.0 create mode 100644 rollup create mode 100644 src/components/chartTheme.tsx create mode 100644 src/styles.css create mode 100644 tailwind.config.js create mode 100644 test/my-app/.gitignore create mode 100644 test/my-app/README.md create mode 100644 test/my-app/eslint.config.js create mode 100644 test/my-app/index.html create mode 100644 test/my-app/package-lock.json create mode 100644 test/my-app/package.json create mode 100644 test/my-app/public/favicon.svg create mode 100644 test/my-app/public/icons.svg create mode 100644 test/my-app/src/App.css create mode 100644 test/my-app/src/App.jsx create mode 100644 test/my-app/src/assets/hero.png create mode 100644 test/my-app/src/assets/react.svg create mode 100644 test/my-app/src/assets/vite.svg create mode 100644 test/my-app/src/index.css create mode 100644 test/my-app/src/main.jsx create mode 100644 test/my-app/vite.config.js create mode 100644 ts.config.json create mode 100644 tsup.config.ts diff --git a/dist/styles.css b/dist/styles.css new file mode 100644 index 00000000..81d7b699 --- /dev/null +++ b/dist/styles.css @@ -0,0 +1,2 @@ +/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.rounded{border-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/examples/application-example.js b/examples/application-example.js index a274ea66..f67076b5 100644 --- a/examples/application-example.js +++ b/examples/application-example.js @@ -7,9 +7,9 @@ import { } from "public-sdk"; function App() { - const nodeId = ""; - const tokenId = ""; - const token = ""; +const tokenId = "itATCNCVamYNmwfdeBumQMwS"; +const token = "Evd8wL35Xt4tNQOXP11YddiRHtM74jqw3JZYuIaPmnWxNozbmnNTUfVaqXmQERV1"; +const nodeId = "20deeee8-f8ae-11ee-9dd8-c3aa61afe2fb"; const client = anedyaClientInit(tokenId, token); diff --git a/package-lock.json b/package-lock.json index 2d81a607..ebb5411a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,778 +9,3940 @@ "version": "5.5.0", "license": "ISC", "dependencies": { - "@anedyasystems/anedya-frontend-sdk": "^0.0.2", + "@anedyasystems/anedya-frontend-sdk": "^0.1.1", "@types/d3": "^7.4.3", "d3": "^7.9.0" }, "devDependencies": { - "@types/react": "^19.2.2", - "@types/react-dom": "^19.2.1", - "typescript": "^5.9.3" + "@base-ui/react": "^1.6.0", + "@tailwindcss/cli": "^4.3.2", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.3.2", + "tsup": "^8.5.1", + "typescript": "^7.0.2" + }, + "peerDependencies": { + "@base-ui/react": "^1.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/@anedyasystems/anedya-frontend-sdk": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@anedyasystems/anedya-frontend-sdk/-/anedya-frontend-sdk-0.0.2.tgz", - "integrity": "sha512-RHV+ljH+X0HaQqG7WQoKVyZjIk/En9CK5xaOrGFNAnC6O3zFW9+M/M01DKDUnW4oQK3OFWTZBRbgN75UCModrA==", - "license": "Apache-2.0" + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@anedyasystems/anedya-frontend-sdk/-/anedya-frontend-sdk-0.1.1.tgz", + "integrity": "sha512-pbwy0Tf+/Oiw+FklKp4lPsr2Ej7Cxe4mD1u02U6q9EeKrGrrLgqLPuxmc0+6uAVAU34TLJnIyF1fnj3bjeHe8Q==", + "license": "Apache-2.0", + "dependencies": { + "cbor-x": "^1.6.4" + } }, - "node_modules/@types/d3": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", - "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base-ui/react": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@base-ui/react/-/react-1.6.0.tgz", + "integrity": "sha512-/jzjTWJYXhRFO45Bev9lc3cHbmjzCMpUqbMZ2AgKy/z25mY9B6shGSNcXcjQar9n5doM0KYW1W8fcFv2jZBuMw==", + "dev": true, "license": "MIT", "dependencies": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-color": "*", - "@types/d3-contour": "*", - "@types/d3-delaunay": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-fetch": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-random": "*", - "@types/d3-scale": "*", - "@types/d3-scale-chromatic": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-zoom": "*" + "@babel/runtime": "^7.29.2", + "@base-ui/utils": "0.3.1", + "@floating-ui/react-dom": "^2.1.8", + "@floating-ui/utils": "^0.2.11", + "use-sync-external-store": "^1.6.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@date-fns/tz": "^1.2.0", + "@types/react": "^17 || ^18 || ^19", + "date-fns": "^4.0.0", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@date-fns/tz": { + "optional": true + }, + "@types/react": { + "optional": true + }, + "date-fns": { + "optional": true + } } }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "node_modules/@base-ui/utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@base-ui/utils/-/utils-0.3.1.tgz", + "integrity": "sha512-gFFiltORVmW/N6IILTGxizP3PBpVpysqML1ALY5Vk0mH+7faVkCknOU31goYHN5Aoek2dkjxva1XOD2Ce9WuIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@floating-ui/utils": "^0.2.11", + "reselect": "^5.2.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "@types/react": "^17 || ^18 || ^19", + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@cbor-extract/cbor-extract-darwin-arm64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-arm64/-/cbor-extract-darwin-arm64-2.2.2.tgz", + "integrity": "sha512-ZKZ/F8US7JR92J4DMct6cLW/Y66o2K576+zjlEN/MevH70bFIsB10wkZEQPLzl2oNh2SMGy55xpJ9JoBRl5DOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@cbor-extract/cbor-extract-darwin-x64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-darwin-x64/-/cbor-extract-darwin-x64-2.2.2.tgz", + "integrity": "sha512-32b1mgc+P61Js+KW9VZv/c+xRw5EfmOcPx990JbCBSkYJFY0l25VinvyyWfl+3KjibQmAcYwmyzKF9J4DyKP/Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-arm": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm/-/cbor-extract-linux-arm-2.2.2.tgz", + "integrity": "sha512-tNg0za41TpQfkhWjptD+0gSD2fggMiDCSacuIeELyb2xZhr7PrhPe5h66Jc67B/5dmpIhI2QOUtv4SBsricyYQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-arm64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-arm64/-/cbor-extract-linux-arm64-2.2.2.tgz", + "integrity": "sha512-wfqgzqCAy/Vn8i6WVIh7qZd0DdBFaWBjPdB6ma+Wihcjv0gHqD/mw3ouVv7kbbUNrab6dKEx/w3xQZEdeXIlzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-linux-x64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-linux-x64/-/cbor-extract-linux-x64-2.2.2.tgz", + "integrity": "sha512-rpiLnVEsqtPJ+mXTdx1rfz4RtUGYIUg2rUAZgd1KjiC1SehYUSkJN7Yh+aVfSjvCGtVP0/bfkQkXpPXKbmSUaA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@cbor-extract/cbor-extract-win32-x64": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@cbor-extract/cbor-extract-win32-x64/-/cbor-extract-win32-x64-2.2.2.tgz", + "integrity": "sha512-dI+9P7cfWxkTQ+oE+7Aa6onEn92PHgfWXZivjNheCRmTBDBf2fx6RyTi0cmgpYLnD1KLZK9ZYrMxaPZ4oiXhGA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, - "node_modules/@types/d3-axis": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", - "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/cli": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.3.2.tgz", + "integrity": "sha512-Fzt+HrIZHDlkRYKdLMBeufaroaPvwCBG70sMLdmurdeadNMO/LxbmT8Sbb+P83ep0iAlAImettb7Y+rO+37rXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@parcel/watcher": "2.5.1", + "@tailwindcss/node": "4.3.2", + "@tailwindcss/oxide": "4.3.2", + "enhanced-resolve": "5.21.6", + "mri": "^1.2.0", + "picocolors": "^1.1.1", + "tailwindcss": "4.3.2" + }, + "bin": { + "tailwindcss": "dist/index.mjs" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz", + "integrity": "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.2" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.2.tgz", + "integrity": "sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-x64": "4.3.2", + "@tailwindcss/oxide-freebsd-x64": "4.3.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-x64-musl": "4.3.2", + "@tailwindcss/oxide-wasm32-wasi": "4.3.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.2" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz", + "integrity": "sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz", + "integrity": "sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz", + "integrity": "sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz", + "integrity": "sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz", + "integrity": "sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz", + "integrity": "sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz", + "integrity": "sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz", + "integrity": "sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz", + "integrity": "sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz", + "integrity": "sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz", + "integrity": "sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz", + "integrity": "sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cbor-extract": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cbor-extract/-/cbor-extract-2.2.2.tgz", + "integrity": "sha512-hlSxxI9XO2yQfe9g6msd3g4xCfDqK5T5P0fRMLuaLHhxn4ViPrm+a+MUfhrvH2W962RGxcBwEGzLQyjbDG1gng==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.1.1" + }, + "bin": { + "download-cbor-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@cbor-extract/cbor-extract-darwin-arm64": "2.2.2", + "@cbor-extract/cbor-extract-darwin-x64": "2.2.2", + "@cbor-extract/cbor-extract-linux-arm": "2.2.2", + "@cbor-extract/cbor-extract-linux-arm64": "2.2.2", + "@cbor-extract/cbor-extract-linux-x64": "2.2.2", + "@cbor-extract/cbor-extract-win32-x64": "2.2.2" + } + }, + "node_modules/cbor-x": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/cbor-x/-/cbor-x-1.6.4.tgz", + "integrity": "sha512-UGKHjp6RHC6QuZ2yy5LCKm7MojM4716DwoSaqwQpaH4DvZvbBTGcoDNTiG9Y2lByXZYFEs9WRkS5tLl96IrF1Q==", + "license": "MIT", + "optionalDependencies": { + "cbor-extract": "^2.2.2" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { - "@types/d3-selection": "*" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/@types/d3-brush": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", - "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", - "license": "MIT", + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", "dependencies": { - "@types/d3-selection": "*" + "robust-predicates": "^3.0.2" } }, - "node_modules/@types/d3-chord": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", - "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } }, - "node_modules/@types/d3-contour": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", - "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "dev": true, "license": "MIT", "dependencies": { - "@types/d3-array": "*", - "@types/geojson": "*" + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", - "license": "MIT" - }, - "node_modules/@types/d3-dispatch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", - "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", - "license": "MIT" - }, - "node_modules/@types/d3-drag": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", - "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "node_modules/esbuild": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, - "node_modules/@types/d3-dsv": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", - "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" - }, - "node_modules/@types/d3-fetch": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", - "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/d3-dsv": "*" + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@types/d3-force": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", - "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", - "license": "MIT" - }, - "node_modules/@types/d3-format": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", - "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", - "license": "MIT" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/geojson": "*" + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" } }, - "node_modules/@types/d3-hierarchy": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", - "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@types/d3-color": "*" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-polygon": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", - "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", - "license": "MIT" - }, - "node_modules/@types/d3-quadtree": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", - "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", - "license": "MIT" - }, - "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", - "license": "MIT" + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "dependencies": { - "@types/d3-time": "*" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", - "license": "MIT" - }, - "node_modules/@types/d3-selection": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", - "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", - "license": "MIT" + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/@types/d3-shape": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", - "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-path": "*" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-time-format": { + "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, - "node_modules/@types/d3-transition": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", - "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, "license": "MIT", "dependencies": { - "@types/d3-selection": "*" + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" + "engines": { + "node": ">=0.12.0" } }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } }, - "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", "dev": true, "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", "dependencies": { - "csstype": "^3.0.2" + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@types/react-dom": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", - "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 10" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/d3": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", - "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", - "license": "ISC", - "dependencies": { - "d3-array": "3", - "d3-axis": "3", - "d3-brush": "3", - "d3-chord": "3", - "d3-color": "3", - "d3-contour": "4", - "d3-delaunay": "6", - "d3-dispatch": "3", - "d3-drag": "3", - "d3-dsv": "3", - "d3-ease": "3", - "d3-fetch": "3", - "d3-force": "3", - "d3-format": "3", - "d3-geo": "3", - "d3-hierarchy": "3", - "d3-interpolate": "3", - "d3-path": "3", - "d3-polygon": "3", - "d3-quadtree": "3", - "d3-random": "3", - "d3-scale": "4", - "d3-scale-chromatic": "3", - "d3-selection": "3", - "d3-shape": "3", - "d3-time": "3", - "d3-time-format": "4", - "d3-timer": "3", - "d3-transition": "3", - "d3-zoom": "3" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/d3-axis": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", - "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", - "license": "ISC", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/d3-brush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", - "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "3", - "d3-transition": "3" + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/d3-chord": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", - "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", - "license": "ISC", - "dependencies": { - "d3-path": "1 - 3" - }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/d3-contour": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", - "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", - "license": "ISC", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-array": "^3.2.0" - }, - "engines": { - "node": ">=12" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/d3-delaunay": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", - "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", - "license": "ISC", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", "dependencies": { - "delaunator": "5" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=12" + "node": ">=8.6" } }, - "node_modules/d3-dispatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", - "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", - "license": "ISC", + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/d3-drag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", - "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", - "license": "ISC", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-dispatch": "1 - 3", - "d3-selection": "3" - }, - "engines": { - "node": ">=12" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, - "node_modules/d3-dsv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", - "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", - "license": "ISC", + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", + "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==", + "license": "MIT", + "optional": true, "dependencies": { - "commander": "7", - "iconv-lite": "0.6", - "rw": "1" + "detect-libc": "^2.0.1" }, "bin": { - "csv2json": "bin/dsv2json.js", - "csv2tsv": "bin/dsv2dsv.js", - "dsv2dsv": "bin/dsv2dsv.js", - "dsv2json": "bin/dsv2json.js", - "json2csv": "bin/json2dsv.js", - "json2dsv": "bin/json2dsv.js", - "json2tsv": "bin/json2dsv.js", - "tsv2csv": "bin/dsv2dsv.js", - "tsv2json": "bin/dsv2json.js" - }, - "engines": { - "node": ">=12" + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" } }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", + "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/d3-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", - "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", - "license": "ISC", - "dependencies": { - "d3-dsv": "1 - 3" - }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-force": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", - "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", - "license": "ISC", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-quadtree": "1 - 3", - "d3-timer": "1 - 3" - }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "license": "ISC", + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 6" } }, - "node_modules/d3-geo": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", - "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", - "license": "ISC", + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-array": "2.5.0 - 3" + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, - "engines": { - "node": ">=12" + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/d3-hierarchy": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", - "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", - "license": "ISC", + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-color": "1 - 3" + "scheduler": "^0.27.0" }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", + "node_modules/reselect": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/d3-polygon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", - "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", - "license": "ISC", + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, "engines": { - "node": ">=12" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" } }, - "node_modules/d3-quadtree": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", - "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", - "license": "ISC", + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=12" + "node": ">= 12" } }, - "node_modules/d3-random": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", - "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", - "license": "ISC", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-interpolate": "1 - 3" - }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 6" } }, - "node_modules/d3-selection": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", - "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", - "license": "ISC", + "node_modules/tailwindcss": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", + "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" + "any-promise": "^1.0.0" } }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-array": "2 - 3" + "thenify": ">= 3.1.0 < 4" }, "engines": { - "node": ">=12" + "node": ">=0.8" } }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-time": "1 - 3" + "fdir": "^6.5.0", + "picomatch": "^4.0.4" }, "engines": { - "node": ">=12" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, - "peerDependencies": { - "d3-selection": "2 - 3" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "license": "ISC", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" + "is-number": "^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=8.0" } }, - "node_modules/delaunator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", - "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", - "license": "ISC", - "dependencies": { - "robust-predicates": "^3.0.2" + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" } }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tsup": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", + "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.27.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "^0.7.6", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" + "node": ">=18" + }, + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } } }, - "node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "license": "Unlicense" - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "tsc": "bin/tsc" }, "engines": { - "node": ">=14.17" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } } } diff --git a/package.json b/package.json index 29b6f3cf..58657ce6 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,21 @@ "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", + "files": [ + "dist" + ], + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./styles.css": "./dist/styles.css" + }, "scripts": { - "build": "rollup -c --bundleConfigAsCjs", - "clean": "rm -rf dist node_modules package-lock.json", - "test": "echo \"Error: no test specified\" && exit 1" + "build:css": "tailwindcss -i src/styles.css -o dist/styles.css --minify", + "build:js": "tsup", + "build": "npm run build:css && npm run build:js", + "typecheck": "tsc --noEmit" }, "repository": { "type": "git", @@ -19,13 +30,22 @@ }, "license": "ISC", "dependencies": { - "@anedyasystems/anedya-frontend-sdk": "^0.0.2", + "@anedyasystems/anedya-frontend-sdk": "^0.1.1", "@types/d3": "^7.4.3", "d3": "^7.9.0" }, + "peerDependencies": { + "@base-ui/react": "^1.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, "devDependencies": { - "@types/react": "^19.2.2", - "@types/react-dom": "^19.2.1", - "typescript": "^5.9.3" + "@base-ui/react": "^1.6.0", + "@tailwindcss/cli": "^4.3.2", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.3.2", + "tsup": "^8.5.1", + "typescript": "^7.0.2" } } diff --git a/public-widget-sdk@5.5.0 b/public-widget-sdk@5.5.0 new file mode 100644 index 00000000..e69de29b diff --git a/rollup b/rollup new file mode 100644 index 00000000..e69de29b diff --git a/src/components/ChartWidget.tsx b/src/components/ChartWidget.tsx index d0d644b0..e7979aaf 100644 --- a/src/components/ChartWidget.tsx +++ b/src/components/ChartWidget.tsx @@ -1,324 +1,263 @@ -import React, { useEffect, useRef, useState } from "react"; +import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import * as d3 from "d3"; - - -import { CSSProperties } from "react"; -import "../../src/index.css" +import { Tooltip } from "@base-ui/react/tooltip"; import { validateRequiredProps } from "../helpers/validate"; import { defaultDateFormatter, formatDate, formatNumber } from "../helpers/formatDate"; - -function computeBottomMargin(ticks: string[]) { - if (!ticks.length) return 40; - - // estimate width of text based on average character width - const longest = ticks.reduce((a, b) => (a.length > b.length ? a : b), ""); - const approxCharWidth = 7; // px - const approximateTextWidth = longest.length * approxCharWidth; - - // because labels rotate -30deg, height β‰ˆ width * sin(30Β°) - const estimatedHeight = approximateTextWidth * 0.5; - - return Math.max(40, estimatedHeight + 20); // + extra padding -} +import { + ChartStyleSet, + ThemeName, + DEFAULT_THEME, + themes, + mergeStyleSets, + ResponsiveStyleSet, + resolveResponsiveStyle, +} from "./chartTheme"; + +// Re-exported so consumers only ever need to import from ChartWidget, +// e.g. `import { ChartWidget, defineStyleRules } from "your-sdk"`. +export type { ChartStyleSet, ThemeName, ResponsiveStyleSet, Breakpoint } from "./chartTheme"; +export { defineStyleRules, lightTheme, darkTheme, themes, BREAKPOINTS } from "./chartTheme"; /* ------------------------ Types ------------------------ */ export interface ChartDataPoint { timestamp: number; value: number; } + type WidgetState = { - value?: any; - loading?: boolean; - error?: string | null; // βœ… matches your React state + data: ChartDataPoint[]; + loading: boolean; + error: string | null; }; - -interface ChartStyleSet { - container?: CSSProperties; - title?: CSSProperties; - tooltip?: CSSProperties; - axis?: CSSProperties; - chart?: { - strokeColor?: string; - strokeWidth?: number; - gradientColors?: [string, string]; - dotRadius?: number; - }; - fontFamily:string -} -type StylesInput = - | ChartStyleSet - | ((state: WidgetState) => ChartStyleSet); +// `styles` accepts either a plain object, or a function that receives the +// widget's current state (data/loading/error) and returns a style set β€” +// useful if styling should depend on load state, not just the data values. +// NOTE: this is always UNCONDITIONAL fixed styling β€” same at every screen +// size. Use `responsiveStyles` (below) for per-breakpoint overrides. +type StylesInput = ChartStyleSet | ((state: WidgetState) => ChartStyleSet); export interface ChartWidgetProps { client: any; nodeId: string; variable: string; - from:number, - to:number, - limit?:number, + from: number; + to: number; + limit?: number; title?: string; + /** Base color theme. Defaults to "light". Overridden per-token by `styles`, `responsiveStyles`, and `onStyleChange`. */ + theme?: ThemeName; + /** Fixed styling, unconditional across all screen/container sizes. */ styles?: StylesInput; - tooltipFormatter?: (d: ChartDataPoint) => string; - tickCount?: number; // number of ticks on x axis (default: 4) - tickFormatter?: (d: Date) => string; // optional custom formatter - xTickFormat?: string | ((d: Date) => string); // date formatting - yTickFormat?: string | ((v: number) => string); // numeric formatting - tooltipFormat?: string | ((d: ChartDataPoint) => string); - onStyleChange?:(data:ChartDataPoint[]) =>{} + /** + * Per-breakpoint styling, layered on top of `styles`. Mobile-first: + * `base` always applies, then `sm`/`md`/`lg`/`xl` apply additionally + * once the widget's own measured container width crosses that + * breakpoint. This measures the widget's OWN box (container-query + * style), not the browser window, so it behaves correctly no matter + * where it's embedded. + * + * responsiveStyles={{ + * base: { chart: { dotRadius: 2, tickFontSize: 8 } }, + * md: { chart: { dotRadius: 3.5, tickFontSize: 10 } }, + * lg: { chart: { dotRadius: 4.5, tickFontSize: 12 } }, + * }} + */ + responsiveStyles?: ResponsiveStyleSet; + tooltipFormat?: (d: ChartDataPoint) => string; + tickCount?: number; + xTickFormat?: string | ((d: Date) => string); + yTickFormat?: string | ((v: number) => string); + /** + * Called with the fetched data whenever it changes. Return a ChartStyleSet + * to override styling conditionally β€” e.g. recolor the line when the + * latest value crosses a threshold. Pair with `defineStyleRules(...)` for + * a declarative shorthand instead of writing this by hand: + * + * onStyleChange={defineStyleRules([ + * { when: (d) => d.value > 80, style: { chart: { strokeColor: "#dc2626" } } }, + * { when: (d) => d.value < 20, style: { chart: { strokeColor: "#2563eb" } } }, + * ])} + */ + onStyleChange?: (data: ChartDataPoint[]) => ChartStyleSet | void; + /** + * Fixed pixel width. If omitted, the chart is fully RESPONSIVE β€” it + * fills whatever width its parent container gives it, tracked live via + * ResizeObserver. Set this only if you specifically want a non-fluid, + * constant-size chart. + */ + width?: number; + /** + * Fixed pixel height. If omitted while `width` is also omitted, height + * is derived from `aspectRatio` relative to the measured container + * width, so the chart keeps sensible proportions at any size. + */ + height?: number; + /** Width-to-height ratio used to derive height when the chart is responsive (no fixed height given). Defaults to 1.6 (800x500). */ + aspectRatio?: number; + /** + * Lower/upper bounds (px) on the RESPONSIVE size β€” ignored entirely if + * `width`/`height` are set to a fixed value, since those already mean + * "constant, don't resize at all." These only kick in for the fluid + * (no fixed width/height) case, so the chart stops shrinking once the + * container gets very small, and stops growing once it gets very large. + * Defaults: minWidth 280, maxWidth 1200, minHeight 200, maxHeight 700. + * Pass your own to override β€” your values always take precedence over + * these defaults. + */ + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; } -/* ------------------------ Helpers ------------------------ */ -const normalizeSx = (sx: Record | undefined): Record => { - if (!sx) return {}; - if (Array.isArray(sx)) return Object.assign({}, ...sx); - if (typeof sx === "function") return sx({}) as Record; - return sx as Record; -}; +// Fallback size used only for the very first render, before ResizeObserver +// has reported the real container width (e.g. during SSR or the first +// paint frame). Once measured, `measuredWidth` takes over. +const FALLBACK_WIDTH = 800; +const DEFAULT_ASPECT_RATIO = 800 / 500; +const MARGIN = { top: 16, right: 16, bottom: 36, left: 44 }; -const toDateSafe = (ts: number): Date => { - // If ts < 1e12, treat as seconds -> convert to ms - if (ts < 1e12) return new Date(ts * 1000); +// Default responsive bounds β€” only used when the chart is fluid (no fixed +// width/height passed) and the caller hasn't supplied their own bounds. +// These exist so the chart can't shrink into an unreadable sliver on a +// tiny screen, or stretch absurdly wide/tall on a huge one. +const DEFAULT_MIN_WIDTH = 280; +const DEFAULT_MAX_WIDTH = 1200; +const DEFAULT_MIN_HEIGHT = 200; +const DEFAULT_MAX_HEIGHT = 700; - return new Date(ts); -}; - -/* ------------------------ Defaults ------------------------ */ -const defaultFontFamily = "Roboto, sans-serif"; - -const defaultStyles: Required = { - container: { - width: 400, - height: 250, - padding: 2, - margin: 0, - display: "flex", - flexDirection: "column", - justifyContent: "flex-start", - alignItems: "center", - borderRadius: 10, - boxSizing: "border-box", -gap:0, - background: "rgb(248, 249, 250)", - border: "1px solid rgba(211, 216, 220, 1)", - - - textAlign: "center", - fontFamily: defaultFontFamily, - }, - title: { - - fontWeight: 600, - color: "rgba(0,0,0,0.75)", - // marginBottom: 1, - fontFamily: defaultFontFamily, - }, - tooltip: { - background: "rgba(0,0,0,0.75)", - - color: "#ffffff", - - borderRadius: "6px", - padding: "6px 10px", - fontSize: "12px", - fontFamily: defaultFontFamily, - }, - axis: { - color: "#666", - fontSize: "11px", - fontFamily:defaultFontFamily, - - }, - chart: { - strokeColor: "#1e88e5", - strokeWidth: 2, - gradientColors: ["#1e88e5", "#90caf9"], - dotRadius: 4, - - }, - fontFamily:defaultFontFamily - - -}; +const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max); +const toDateSafe = (ts: number): Date => (ts < 1e12 ? new Date(ts * 1000) : new Date(ts)); -// ---- ChartWidget ---- +/* ------------------------ ChartWidget ------------------------ */ export const ChartWidget: React.FC = ({ client, nodeId, variable, from, to, - limit=20, + limit = 20, title = "Latest Data", + theme = DEFAULT_THEME, styles = {}, - tooltipFormatter = (d) => - `${new Date( - new Date(d.timestamp < 1e12 ? d.timestamp * 1000 : d.timestamp) - ).toLocaleString(undefined, { - month: "short", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - hour12: true, - })}: ${d.value}`, - tickCount = 4, - tickFormatter, + responsiveStyles, + tooltipFormat, + tickCount = 4, xTickFormat, yTickFormat, - tooltipFormat, - onStyleChange + onStyleChange, + width: fixedWidth, + height: fixedHeight, + aspectRatio = DEFAULT_ASPECT_RATIO, + minWidth = DEFAULT_MIN_WIDTH, + maxWidth = DEFAULT_MAX_WIDTH, + minHeight = DEFAULT_MIN_HEIGHT, + maxHeight = DEFAULT_MAX_HEIGHT, }) => { - - validateRequiredProps( + validateRequiredProps( "Chart Widget", - { client, nodeId, variable,from,to }, - ["client", "nodeId", "variable","from time","to time"] + { client, nodeId, variable, from, to }, + ["client", "nodeId", "variable", "from time", "to time"] ); - const resolvedXFormatter = - typeof xTickFormat === "string" - ? (d: Date) => formatDate(d, xTickFormat) - : xTickFormat; - -const resolvedYFormatter = - typeof yTickFormat === "string" - ? (v: number) => formatNumber(v, yTickFormat) - : yTickFormat; - -const resolvedTooltipFormatter = - typeof tooltipFormat === "string" - ? (d: ChartDataPoint) => - `${formatDate(toDateSafe(d.timestamp), tooltipFormat)}: ${d.value}` - : tooltipFormat; - - - // Refs + state - const svgRef = useRef(null); - const tooltipNodeRef = useRef(null); - const [data, setData] = useState([ - // { timestamp: Date.now() - 60000, value: 33 }, - // { timestamp: Date.now() - 30000, value: 44 }, - // { timestamp: Date.now(), value: 38 }, - ]); + /* ------------------------------------------------------------ + * Responsive sizing + * ------------------------------------------------------------ + * If `fixedWidth` is provided, the chart behaves exactly like + * before (constant pixel size, same on every screen). Otherwise + * we measure the wrapper div's real rendered width via + * ResizeObserver and recompute on every resize β€” so the chart + * genuinely fills whatever space it's given, live, without a + * page reload. + * ---------------------------------------------------------- */ + const containerRef = useRef(null); + const [measuredWidth, setMeasuredWidth] = useState(FALLBACK_WIDTH); + + useLayoutEffect(() => { + // Fixed width means we never need to observe β€” skip entirely. + if (fixedWidth != null) return; + const el = containerRef.current; + if (!el || typeof ResizeObserver === "undefined") return; + + const observer = new ResizeObserver((entries) => { + const entry = entries[0]; + if (!entry) return; + const w = Math.round(entry.contentRect.width); + // Guard against 0-width flashes (e.g. element briefly display:none) + // which would otherwise collapse the chart to nothing. + if (w > 0) setMeasuredWidth(w); + }); + + observer.observe(el); + return () => observer.disconnect(); + }, [fixedWidth]); + + const effectiveWidth = fixedWidth ?? clamp(measuredWidth, minWidth, maxWidth); + const effectiveHeight = + fixedHeight ?? clamp(Math.round(effectiveWidth / aspectRatio), minHeight, maxHeight); + + const CHART_W = effectiveWidth - MARGIN.left - MARGIN.right; + const CHART_H = effectiveHeight - MARGIN.top - MARGIN.bottom; + + // Fewer x-axis ticks on narrow containers so labels don't overlap. + // Only kicks in below the widths where crowding actually becomes a + // problem; larger containers use the caller's requested tickCount as-is. + const effectiveTickCount = + effectiveWidth < 380 ? Math.min(tickCount, 2) : effectiveWidth < 560 ? Math.min(tickCount, 3) : tickCount; + + const [node, setNode] = useState(null); + const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - const [node, setNode] = useState(null); - - - const state = { data, loading, error }; // <-- your widget’s internal state - -// Resolve function or static style object -const [dynamicStyles, setDynamicStyles] = useState>({}); -const baseResolvedStyles = - typeof styles === "function" ? styles(state) : styles || {}; + // Holds only the *data-driven* layer of styling (from `styles` prop + + // `onStyleChange`). Theme and responsiveStyles are applied separately + // below so that resizing or switching `theme` never requires waiting + // on the data-fetch effect. + const [dynamicStyle, setDynamicStyle] = useState({}); -const resolvedStyles = { - container: { ...baseResolvedStyles.container, ...dynamicStyles?.container }, - title: { ...baseResolvedStyles.title, ...dynamicStyles?.title }, - tooltip: { ...baseResolvedStyles.tooltip, ...dynamicStyles?.tooltip }, - chart: { ...baseResolvedStyles.chart, ...dynamicStyles?.chart }, - axis: { ...baseResolvedStyles.axis, ...dynamicStyles?.axis }, - fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily, -}; const mountedRef = useRef(false); - const failureCountRef = useRef(0); const isFetchingRef = useRef(false); - const MAX_FAILURES = 3; - - // ---- Normalize Styles ---- - const containerSx = normalizeSx(resolvedStyles?.container); - const titleSx = normalizeSx(resolvedStyles?.title); - const tooltipSx = normalizeSx(resolvedStyles?.tooltip); - const chartSx = resolvedStyles.chart ?? {}; - const axisSx = normalizeSx(resolvedStyles?.axis); - - // --- Container dimensions with TypeScript-safe default --- - const containerDefaults: any = defaultStyles.container!; - const width = containerSx.width ?? containerDefaults.width; - const height = containerSx.height ?? containerDefaults.height; - - - // --- Font family handling --- - const globalFontFamily = resolvedStyles?.fontFamily ?? "Roboto"; - const labelFontFamily = titleSx.fontFamily ?? globalFontFamily; - - - - - - - - // --- Scaled font sizes --- - const baseFont = Math.min(Number(width), Number(height)) * 0.15; - // --- Compute font sizes dynamically if not provided by user --- - const labelFont = (resolvedStyles?.title as any)?.fontSize ?? baseFont * 0.6; - - - const strokeColor = chartSx.strokeColor ?? defaultStyles.chart.strokeColor; - const strokeWidth = chartSx.strokeWidth ?? defaultStyles.chart.strokeWidth; - const gradientColors = - chartSx.gradientColors ?? defaultStyles.chart.gradientColors; -const dotRadius = chartSx.dotRadius ?? defaultStyles.chart.dotRadius; - // ---- Fetch Node ---- + // Resolve the node through the client's (rate-limited) Anedya instance useEffect(() => { if (!client || !nodeId) return; - const anedya = (client as any)._anedya; - const createdNode = anedya?.NewNode?.(client, nodeId); - setNode(createdNode); + const anedya = client._anedya; + setNode(anedya?.newNode?.(client, nodeId) ?? null); }, [client, nodeId]); - // ---- Fetch Data ---- + // Fetch data useEffect(() => { + if (!node) return; mountedRef.current = true; - if ( - !node - // || data.length>0 - ) - return; const fetchData = async () => { - if (isFetchingRef.current || failureCountRef.current >= MAX_FAILURES) - return; + if (isFetchingRef.current) return; isFetchingRef.current = true; + setLoading(true); + setError(null); try { - setLoading(true); - setError(null); - // const currentTime = Date.now(); - // const twentyFourHoursAgo = currentTime - 86400 * 1000; -//1732420983000 -//1763956983000 - const req = { - variable, - from: from, - to: to, - limit: limit, - order: "asc", - }; - const res = await node.getData(req); - + const res = await node.getData({ variable, from, to, limit, order: "asc" }); if (!mountedRef.current) return; if (res.isSuccess && res.isDataAvailable) { setData(res.data); - setError(""); - } else { - console.error("error fetching data:", res.error); - setError(res.error.errorMessage); + setData([]); + setError(res.error?.errorMessage ?? "No data available"); } - failureCountRef.current = 0; } catch (err: any) { - console.error("Error fetching chart data:", err); + if (!mountedRef.current) return; setData([]); setError(err?.message ?? "Failed to fetch data"); - failureCountRef.current += 1; } finally { - setLoading(false); - if (mountedRef.current) isFetchingRef.current = false; + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } } }; @@ -326,371 +265,307 @@ const dotRadius = chartSx.dotRadius ?? defaultStyles.chart.dotRadius; return () => { mountedRef.current = false; }; - }, [node, variable]); + }, [node, variable, from, to, limit]); - /* ------------------------ D3 render (dots + line + area + tooltip + axes) ------------------------ */ + // Resolve the `styles` prop (static or function) and `onStyleChange` + // result whenever the data changes, and merge them together. Order + // matters: onStyleChange is applied last so conditional/threshold + // styling always wins over the caller's static `styles` prop. useEffect(() => { - if (!svgRef.current) return; - const svgEl = svgRef.current; - const svg = d3.select(svgEl); - svg.selectAll("*").remove(); - - // If no data, nothing to draw - if (!data || data.length === 0) { - return; - } - - - - // // --- COMPUTE SCALES --- // - // const tempDates = data.map((d) => toDateSafe(d.timestamp)); - // const tempX = d3.scaleTime().domain(d3.extent(tempDates) as [Date, Date]).range([0, 1]); // temp range - // const provisionalTicks = tempX.ticks(tickCount); - - // const tickLabels = provisionalTicks.map((d) => - // resolvedXFormatter ? resolvedXFormatter(d) : defaultDateFormatter(d) - // ); - - // const dynamicBottom = computeBottomMargin(tickLabels); - - // // --- NOW REAL MARGINS --- // - // const margin = { top: 20, right: 20, bottom: dynamicBottom, left: 50 }; - - // // recompute chart area - // const chartW = Math.max(10, width - margin.left - margin.right); - // const chartH = Math.max(10, height - margin.top - margin.bottom); - - // // recompute x with real width - // tempX.range([0, chartW]); - - //.attr("transform", "rotate(-30)") -//margins (leave extra bottom space for rotated ticks) - const margin = { top: 20, right: 20, bottom: 130, left: 50 }; - const chartW = Math.max(10, width - margin.left - margin.right); - const chartH = Math.max(10, height - margin.top - margin.bottom); + const fromStylesProp = + typeof styles === "function" ? styles({ data, loading, error }) : styles; + const fromCallback = onStyleChange?.(data) ?? {}; + + setDynamicStyle(mergeStyleSets(fromStylesProp, fromCallback)); + // Intentionally only re-resolves when the data itself changes, matching + // the original widget's behavior. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + + // Final style resolution, applied in precedence order: + // 1. theme preset (light/dark) β€” base layer + // 2. dynamicStyle (styles prop + onStyleChange) β€” data-driven layer + // 3. responsiveStyles for the current breakpoint β€” highest priority, + // resolved fresh on every render against `effectiveWidth` so a + // live resize is reflected immediately. + const resolvedStyle = useMemo( + () => + mergeStyleSets( + { chart: themes[theme] }, + dynamicStyle, + resolveResponsiveStyle(responsiveStyles, effectiveWidth) + ), + [theme, dynamicStyle, responsiveStyles, effectiveWidth] + ); + const chartStyle:any = resolvedStyle.chart!; // themes[theme] guarantees every ChartColors field is present - // group - const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`); + const { linePath, areaPath, points, xTicks, yTicks } = useMemo(() => { + if (!data.length) { + return { linePath: "", areaPath: "", points: [] as { cx: number; cy: number; point: ChartDataPoint }[], xTicks: [], yTicks: [] }; + } - // parse / convert timestamps to Date safely const dates = data.map((d) => toDateSafe(d.timestamp)); - const x = d3.scaleTime().domain(d3.extent(dates) as [Date, Date]).range([0, chartW]); - const maxY = Math.max(10, d3.max(data, (d) => Number(d.value)) ?? 10); - const y = d3.scaleLinear().domain([0, maxY]).nice().range([chartH, 0]); - - // gradient - const safeGradient = gradientColors ?? ["#1e88e5", "#90caf9"]; - const safeStroke = strokeColor ?? "#1e88e5"; - const safeWidth = strokeWidth ?? 2; - const safeDotRadius = dotRadius ?? 4 - const defs = svg.append("defs"); - - const gradient = defs - .append("linearGradient") - .attr("id", "chartGradient") - .attr("x1", "0%") - .attr("y1", "0%") - .attr("x2", "0%") - .attr("y2", "100%"); - gradient - .append("stop") - .attr("offset", "0%") - .attr("stop-color", safeGradient[0]) - .attr("stop-opacity", 0.5); - gradient - .append("stop") - .attr("offset", "100%") - .attr("stop-color", safeGradient[1]) - .attr("stop-opacity", 0); - - // area - const area = d3 - .area() - .x((d) => x(toDateSafe(d.timestamp))) - .y0(chartH) - .y1((d) => y(d.value)) - .curve(d3.curveMonotoneX); + const x = d3.scaleTime().domain(d3.extent(dates) as [Date, Date]).range([0, CHART_W]); + const maxY = Math.max(10, d3.max(data, (d) => d.value) ?? 10); + const y = d3.scaleLinear().domain([0, maxY]).nice().range([CHART_H, 0]); - g.append("path").datum(data).attr("fill", "url(#chartGradient)").attr("d", area); - - // line const line = d3 .line() .x((d) => x(toDateSafe(d.timestamp))) .y((d) => y(d.value)) .curve(d3.curveMonotoneX); - g.append("path") - .datum(data) - .attr("fill", "none") - .attr("stroke", safeStroke) - .attr("stroke-width", safeWidth) - .attr("d", line); - - // dots - const dotR = computeDotRadius(chartW, chartH, safeDotRadius); - const dots = g - .selectAll(".dot") - .data(data) - .enter() - .append("circle") - .attr("class", "dot") - .attr("cx", (d) => x(toDateSafe(d.timestamp))) - .attr("cy", (d) => y(d.value)) - .attr("r", dotR) - .attr("fill", safeStroke) - .style("cursor", "default"); - - // Tooltip (create single DOM node appended to body) - // Reuse tooltip div if present - let tooltipDiv = tooltipNodeRef.current; - if (!tooltipDiv) { - tooltipDiv = document.createElement("div"); - tooltipNodeRef.current = tooltipDiv; - document.body.appendChild(tooltipDiv); - } - // apply tooltip styles (inline) - const tooltipDefaults: any = defaultStyles.tooltip; - tooltipDiv.style.position = "absolute"; - tooltipDiv.style.pointerEvents = "none"; - tooltipDiv.style.opacity = "0"; - tooltipDiv.style.background = (tooltipSx.backgroundColor ?? tooltipDefaults.background) as string; - tooltipDiv.style.color = (tooltipSx.color ?? tooltipDefaults.color) as string; - tooltipDiv.style.borderRadius = (tooltipSx.borderRadius ?? tooltipDefaults.borderRadius) as string; - tooltipDiv.style.padding = (tooltipSx.padding ?? tooltipDefaults.padding) as string; - tooltipDiv.style.fontSize = (tooltipSx.fontSize ?? tooltipDefaults.fontSize) as string; - tooltipDiv.style.transition = "opacity 120ms"; - - // interactions - dots - .on("mouseover", function (event, d: ChartDataPoint) { - tooltipDiv!.style.opacity = "1"; - tooltipDiv!.innerHTML = resolvedTooltipFormatter - ? resolvedTooltipFormatter(d) - : tooltipFormatter(d); - }) - .on("mousemove", function (event) { - // place tooltip near pointer but keep inside window - const pad = 8; - const left = Math.min(window.innerWidth - 200, event.pageX + pad); - const top = Math.max(8, event.pageY - 36); - tooltipDiv!.style.left = `${left}px`; - tooltipDiv!.style.top = `${top}px`; - }) - .on("mouseout", function () { - tooltipDiv!.style.opacity = "0"; - }); - - // axes - bottom x with custom tick formatting and rotated labels - const xAxis = d3 - .axisBottom(x) - .ticks(tickCount) - .tickFormat((d) => { - if (resolvedXFormatter) return resolvedXFormatter(d as Date); - return defaultDateFormatter(d as Date); - }); - - - const axisDefaults : any = defaultStyles.axis - g.append("g") - .attr("transform", `translate(0,${chartH})`) - .call(xAxis) - .selectAll("text") - .attr("transform", "rotate(-30)") - .style("text-anchor", "end") - .style("font-size", (axisSx.fontSize ?? axisDefaults.fontSize) as string) - .style("fill", (axisSx.color ?? axisDefaults.color) as string) - .style("font-family", (axisSx.fontFamily ?? axisDefaults.fontFamily) as string); - - g.append("g") - .call(d3.axisLeft(y).ticks(5).tickFormat((v) => { - if (resolvedYFormatter) return resolvedYFormatter(v as number); - return String(v); - })) - .selectAll("text") - .style("font-size", (axisSx.fontSize ?? axisDefaults.fontSize) as string) - .style("fill", (axisSx.color ?? axisDefaults.color) as string) - .style("font-family", (axisSx.fontFamily ?? axisDefaults.fontFamily) as string); - - // keep axes inside container by clipping overflow - // Add clipPath so elements don't overflow container boundaries visually - const clipId = `clip-${Math.random().toString(36).slice(2, 9)}`; - svg - .append("defs") - .append("clipPath") - .attr("id", clipId) - .append("rect") - .attr("width", width) - .attr("height", height); - svg.attr("clip-path", `url(#${clipId})`); - - // cleanup on effect re-run - return () => { - // remove tooltip div if created by this component - if (tooltipNodeRef.current) { - try { - tooltipNodeRef.current.remove(); - } catch {} - tooltipNodeRef.current = null; - } - svg.selectAll("*").remove(); - }; - }, [ - data, - width, - height, - strokeColor, - strokeWidth, - gradientColors, - dotRadius, - tickCount, - tickFormatter, - tooltipFormatter, - axisSx, - tooltipSx, - ]); - - - - // Whenever value changes, allow user to modify styles dynamically - useEffect(() => { - if (typeof onStyleChange === "function") { - const updated = onStyleChange(data); - if (updated && typeof updated === "object") { - setDynamicStyles(updated); - } - } - }, [data]); - - /* ------------------------ Helpers ------------------------ */ - function computeDotRadius(chartW: number, chartH: number, requested: number) { - // scale dot radius a bit relative to min dimension but honor requested if provided - const base = Math.max(2, Math.min(chartW, chartH) * 0.012); - return requested ?? Math.round(base); - } - // --- Merge styles safely --- - const mergedContainerSx: CSSProperties = { - ...defaultStyles.container, - ...containerSx, - - }; - const mergedLabelSx: CSSProperties = { - ...defaultStyles.title, - fontSize: labelFont, - ...titleSx, - fontFamily: labelFontFamily, - }; + const area = d3 + .area() + .x((d) => x(toDateSafe(d.timestamp))) + .y0(CHART_H) + .y1((d) => y(d.value)) + .curve(d3.curveMonotoneX); + const points = data.map((d) => ({ + cx: x(toDateSafe(d.timestamp)), + cy: y(d.value), + point: d, + })); + + const xTicks = x.ticks(effectiveTickCount).map((d) => ({ + x: x(d), + label: + typeof xTickFormat === "function" + ? xTickFormat(d) + : typeof xTickFormat === "string" + ? formatDate(d, xTickFormat) + : defaultDateFormatter(d), + })); + + const yTicks = y.ticks(4).map((v) => ({ + y: y(v), + label: + typeof yTickFormat === "function" + ? yTickFormat(v) + : typeof yTickFormat === "string" + ? formatNumber(v, yTickFormat) + : String(v), + })); + + return { linePath: line(data) ?? "", areaPath: area(data) ?? "", points, xTicks, yTicks }; + }, [data, effectiveTickCount, xTickFormat, yTickFormat, CHART_W, CHART_H]); + + const gradientId = useMemo(() => `chart-gradient-${Math.random().toString(36).slice(2, 9)}`, []); return ( -
- {title && ( -

- {title} -

- )} - {loading ? ( -
constant pixel size (still capped at 100% so it + // never overflows a parent narrower than the fixed value). + // Fluid -> fills parent, bounded between minWidth/maxWidth. + width: fixedWidth ?? "100%", + maxWidth: fixedWidth != null ? "100%" : `min(100%, ${maxWidth}px)`, + minWidth: fixedWidth != null ? undefined : minWidth, + minHeight: fixedHeight != null ? undefined : minHeight, + maxHeight: fixedHeight != null ? undefined : maxHeight, + boxSizing: "border-box", + ...resolvedStyle.container, }} > -
-
+ {title && ( +

+ {title} +

+ )} + + {loading ? ( +
+
+ +
) : error ? ( -
-
+
-{error} -
- + > + {error}
- ) : data?.length === 0? -
+ ) : data.length === 0 ? ( +
+ No data available +
+ ) : ( + // Base UI's Tooltip primitives handle positioning, portaling (so the + // popup escapes SVG clipping), and accessibility (focus/hover/ARIA). + // They apply zero visual styling themselves β€” all the look is defined + // via the `style` props passed to Tooltip.Popup etc. below. + + -
-{ "No data available"} -
- -
: - ( - + + + + + + + + + + + + {/* X axis */} + + {xTicks.map((t, i) => ( + + {t.label} + + ))} + + {/* Y axis */} + {yTicks.map((t, i) => ( + + {t.label} + + ))} + + {points.map(({ cx, cy, point }, i) => ( + + + } + /> + + + + {tooltipFormat + ? tooltipFormat(point) + : `${toDateSafe(point.timestamp).toLocaleString()}: ${point.value}`} + + + + + ))} + + + )}
); }; - -//add customizable toolips, stroke width and color, and title obvs , timestamps for get data request -//match customization and failsafes to latest data -//documentation -//modify anedya client as well -//adjust rateLimitMs -//how do i also ensure that the y axis labels dont crpss the container card border , all labels are contained within th container card - -//ftick format functions -//responsiveness -//frequesncy of ticks -//show all widgets -//documentation -//consistent widget default styling , default color palette and theme -//beta launch -//how to add docs in npm --- add them in read me +// TODO: axis-specific style overrides, per-element font family cascade, +// dot-decimation on very narrow/dense containers. \ No newline at end of file diff --git a/src/components/LatestDataGauge.tsx b/src/components/LatestDataGauge.tsx index 1d8c9719..f9978b83 100644 --- a/src/components/LatestDataGauge.tsx +++ b/src/components/LatestDataGauge.tsx @@ -218,6 +218,46 @@ export const LatestDataGauge: React.FC = ({ ["client", "nodeId", "variable"] ); + const streamId="019d3dce-2043-7dbe-86fe-69387b378107" + const streamUrl="wss://ZxBpErVPCj.acs-r1.ap-in-1.anedya.io/v1/streams/connect" + + useEffect(() => { + if (!client || !nodeId || !streamId || !streamUrl) return; + mountedRef.current = true; + + const anedya = (client as any)._anedya as Anedya; + + const node = anedya.NewNode(client, nodeId); + console.log(node,"node") + const stream = node.getStream(streamId, streamUrl); + + + stream.onData((data: any) => { + if (!mountedRef.current) return; + console.log("Stream Data:", data); + }); + + stream.onError((err: any) => { + if (!mountedRef.current) return; + console.error("Stream Error:", err); + }); + + stream + .connect() + .then(() => { + if (mountedRef.current) console.log("Stream connected"); + }) + .catch((err: any) => { + console.error("Stream connect failed:", err); + }); + + return () => { + mountedRef.current = false; + stream.disconnect(); + console.log("Stream disconnected"); + }; + }, [client, nodeId, streamId, streamUrl]); + const [value,setValue] = useState(null) diff --git a/src/components/chartTheme.tsx b/src/components/chartTheme.tsx new file mode 100644 index 00000000..e525d79e --- /dev/null +++ b/src/components/chartTheme.tsx @@ -0,0 +1,222 @@ +import type { ChartDataPoint } from "./ChartWidget"; + +/* ============================================================ + * ChartColors + * ------------------------------------------------------------ + * Every color/visual token the chart actually renders with. + * This is intentionally a flat object of *required* fields so + * that `themes.light` / `themes.dark` are guaranteed complete β€” + * no risk of an undefined color slipping through at render time. + * ============================================================ */ +export interface ChartColors { + strokeColor: string; + strokeWidth: number; + gradientColors: [string, string]; + dotRadius: number; + axisColor: string; + tickColor: string; + backgroundColor: string; + borderColor: string; + titleColor: string; + /** Font size (px) for axis tick labels. Exposed so responsiveStyles can shrink it on small screens. */ + tickFontSize: number; + /** Font size (px) for the chart title. Exposed so responsiveStyles can shrink it on small screens. */ + titleFontSize: number; +} + +/* ============================================================ + * ChartStyleSet + * ------------------------------------------------------------ + * This is the shape every styling entry point accepts: + * - the `styles` prop (static or a function of widget state) + * - the return value of `onStyleChange` + * - each `style` inside a `defineStyleRules` rule + * + * `chart` is `Partial` because callers should be + * able to override just one or two tokens (e.g. only strokeColor + * when a threshold is crossed) without having to restate every + * other color. + * ============================================================ */ +export interface ChartStyleSet { + container?: React.CSSProperties; + title?: React.CSSProperties; + chart?: Partial; +} + +/* ============================================================ + * Theme presets + * ------------------------------------------------------------ + * These are the *base layer* of styling β€” applied before the + * user's `styles` prop and before any `onStyleChange` result. + * Add more presets here (e.g. "minimal") as needed; just make + * sure they satisfy ChartColors fully. + * ============================================================ */ +export const lightTheme: ChartColors = { + strokeColor: "#1e88e5", + strokeWidth: 2, + gradientColors: ["#1e88e5", "#90caf9"], + dotRadius: 3.5, + axisColor: "#cbd5e1", + tickColor: "#64748b", + backgroundColor: "#f8fafc", + borderColor: "#e2e8f0", + titleColor: "#0f172a", + tickFontSize: 10, + titleFontSize: 16, +}; + +export const darkTheme: ChartColors = { + strokeColor: "#60a5fa", + strokeWidth: 2, + gradientColors: ["#60a5fa", "#1e3a8a"], + dotRadius: 3.5, + axisColor: "#334155", + tickColor: "#94a3b8", + backgroundColor: "#0f172a", + borderColor: "#1e293b", + titleColor: "#f1f5f9", + tickFontSize: 10, + titleFontSize: 16, +}; + +export const themes = { + light: lightTheme, + dark: darkTheme, +} as const; + +export type ThemeName = keyof typeof themes; + +/** Default theme for every ChartWidget instance unless overridden via the `theme` prop. */ +export const DEFAULT_THEME: ThemeName = "light"; + +/* ============================================================ + * mergeStyleSets + * ------------------------------------------------------------ + * Combines any number of ChartStyleSet objects, left to right, + * where later sets win. Each of container/title/chart is merged + * independently (shallow per-key), so passing only + * `{ chart: { strokeColor: "red" } }` never wipes out the other + * chart tokens that came from an earlier layer (e.g. the theme). + * + * Overall precedence used by ChartWidget (lowest to highest): + * 1. theme preset (light/dark) + * 2. `styles` prop (static object or function of widget state) + * 3. `onStyleChange` result (re-evaluated whenever data changes) + * ============================================================ */ +export function mergeStyleSets( + ...sets: (ChartStyleSet | undefined | null)[] +): ChartStyleSet { + const result: ChartStyleSet = {}; + for (const set of sets) { + if (!set) continue; + result.container = { ...result.container, ...set.container }; + result.title = { ...result.title, ...set.title }; + result.chart = { ...result.chart, ...set.chart }; + } + return result; +} + +/* ============================================================ + * Responsive breakpoints + * ------------------------------------------------------------ + * These are CONTAINER-width breakpoints (measured via + * ResizeObserver on the widget's own wrapper), not viewport/ + * window breakpoints β€” matching CSS container-query semantics + * rather than media-query semantics. That's the right behavior + * for an embeddable widget: it should adapt to the box it's + * placed in (a sidebar, a dashboard tile, a modal), not to the + * size of the browser window, which may be much larger than the + * space actually given to the widget. + * + * Thresholds mirror Tailwind's default breakpoints so the mental + * model transfers directly for anyone used to Tailwind's + * sm:/md:/lg:/xl: prefixes. + * ============================================================ */ +export type Breakpoint = "sm" | "md" | "lg" | "xl"; + +export const BREAKPOINTS: Record = { + sm: 640, + md: 768, + lg: 1024, + xl: 1280, +}; + +/** + * Responsive style map. `base` always applies; each named + * breakpoint applies *in addition*, once the container's + * measured width is >= that breakpoint's threshold β€” mobile + * first, same cascade model as Tailwind's responsive prefixes. + * + * This is a SEPARATE prop from `styles` on purpose: `styles` + * (or a static object) is unconditional fixed styling that + * applies identically at every screen size, while + * `responsiveStyles` is only ever consulted per-breakpoint. + * Passing one doesn't affect how the other behaves. + */ +export type ResponsiveStyleSet = Partial>; + +/** + * Resolves a ResponsiveStyleSet down to a single flat + * ChartStyleSet for the widget's current measured container + * width. Layers are merged in ascending breakpoint order so + * larger breakpoints override smaller ones on overlapping keys, + * exactly like cascading CSS media queries. + */ +export function resolveResponsiveStyle( + responsiveStyles: ResponsiveStyleSet | undefined, + containerWidth: number +): ChartStyleSet { + if (!responsiveStyles) return {}; + + const layers: ChartStyleSet[] = []; + if (responsiveStyles.base) layers.push(responsiveStyles.base); + + (Object.keys(BREAKPOINTS) as Breakpoint[]) + .sort((a, b) => BREAKPOINTS[a] - BREAKPOINTS[b]) + .forEach((bp) => { + if (containerWidth >= BREAKPOINTS[bp] && responsiveStyles[bp]) { + layers.push(responsiveStyles[bp]!); + } + }); + + return mergeStyleSets(...layers); +} + +/* ============================================================ + * StyleRule / defineStyleRules + * ------------------------------------------------------------ + * Sugar for the common "if value crosses some threshold, change + * the styling" pattern, without writing a raw onStyleChange + * callback by hand every time. + * + * `when` is evaluated against the *latest* data point (most + * recent value) plus the full data array, in case a rule needs + * more context (e.g. comparing against an average). + * + * If multiple rules match, their styles are merged in array + * order (later matching rules win on overlapping keys) β€” this + * lets you stack rules like "base warning color" + "critical + * override" instead of only ever applying one. + * + * Usage: + * onStyleChange={defineStyleRules([ + * { when: (d) => d.value > 80, style: { chart: { strokeColor: "#dc2626" } } }, + * { when: (d) => d.value < 20, style: { chart: { strokeColor: "#2563eb" } } }, + * ])} + * ============================================================ */ +export interface StyleRule { + when: (latest: ChartDataPoint, allData: ChartDataPoint[]) => boolean; + style: ChartStyleSet; +} + +export function defineStyleRules( + rules: StyleRule[] +): (data: ChartDataPoint[]) => ChartStyleSet { + return (data: ChartDataPoint[]) => { + const latest = data[data.length - 1]; + if (!latest) return {}; + + const matched = rules.filter((rule) => rule.when(latest, data)); + return mergeStyleSets(...matched.map((rule) => rule.style)); + }; +} \ No newline at end of file diff --git a/src/hooks/AnedyaFrontendClient.ts b/src/hooks/AnedyaFrontendClient.ts index 38f135c0..651cafb6 100644 --- a/src/hooks/AnedyaFrontendClient.ts +++ b/src/hooks/AnedyaFrontendClient.ts @@ -39,13 +39,13 @@ export function anedyaClientInit( } const anedya = new Anedya(); - const config = anedya.NewConfig(tokenId, token); - const client = anedya.NewClient(config); + const config = anedya.newConfig(tokenId, token); + const client = anedya.newClient(config); // --- Patch NewNode with per-node rate limiter --- - const originalNewNode: (...args: any[]) => any = anedya.NewNode.bind(anedya); + const originalNewNode: (...args: any[]) => any = anedya.newNode.bind(anedya); - anedya.NewNode = (...args: any[]): any => { + anedya.newNode = (...args: any[]): any => { const node = originalNewNode(...args); // βœ… now properly typed // Extract nodeId (second argument) diff --git a/src/hooks/Older.ts b/src/hooks/Older.ts index 20cc398b..93fde8cd 100644 --- a/src/hooks/Older.ts +++ b/src/hooks/Older.ts @@ -30,8 +30,8 @@ export function anedyaClientInit( return globalClient; } // Always create fresh instances const anedya = new Anedya(); - const config = anedya.NewConfig(tokenId, token); - const client = anedya.NewClient(config); + const config = anedya.newConfig(tokenId, token); + const client = anedya.newClient(config); if (useGlobal) { globalClient = client; } diff --git a/src/index.css b/src/index.css index 040e0bf7..cb9f1bd6 100644 --- a/src/index.css +++ b/src/index.css @@ -1,3 +1,5 @@ +@import "tailwindcss"; + .pointer-wrapper { position: relative; } diff --git a/src/index.ts b/src/index.ts index 6ab23dd2..2c9253af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export { anedyaClientInit } from "./hooks/AnedyaFrontendClient"; export {LatestDataWidget} from "./hooks/renderLatestData"; export {ChartWidget} from "./components/ChartWidget" +export type { ChartWidgetProps, ChartDataPoint } from "./components/ChartWidget"; export {LatestDataGauge} from "./components/LatestDataGauge" \ No newline at end of file diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 00000000..f1d8c73c --- /dev/null +++ b/src/styles.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000..e69de29b diff --git a/test/my-app/.gitignore b/test/my-app/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/test/my-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/test/my-app/README.md b/test/my-app/README.md new file mode 100644 index 00000000..e16d995e --- /dev/null +++ b/test/my-app/README.md @@ -0,0 +1,18 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. + +Note: This will impact Vite dev & build performances. + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/test/my-app/eslint.config.js b/test/my-app/eslint.config.js new file mode 100644 index 00000000..4fa125da --- /dev/null +++ b/test/my-app/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/test/my-app/index.html b/test/my-app/index.html new file mode 100644 index 00000000..53beb493 --- /dev/null +++ b/test/my-app/index.html @@ -0,0 +1,13 @@ + + + + + + + my-app + + +
+ + + diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json new file mode 100644 index 00000000..3ae766b8 --- /dev/null +++ b/test/my-app/package-lock.json @@ -0,0 +1,2648 @@ +{ + "name": "my-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "my-app", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@babel/core": "^7.29.0", + "@eslint/js": "^9.39.4", + "@rolldown/plugin-babel": "^0.2.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "babel-plugin-react-compiler": "^1.0.0", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", + "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", + "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", + "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", + "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.122.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", + "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", + "integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz", + "integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz", + "integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz", + "integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz", + "integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz", + "integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz", + "integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz", + "integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz", + "integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz", + "integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz", + "integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz", + "integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/plugin-babel": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.2.tgz", + "integrity": "sha512-q9pE8+47bQNHb5eWVcE6oXppA+JTSwvnrhH53m0ZuHuK5MLvwsLoWrWzBTFQqQ06BVxz1gp0HblLsch8o6pvZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=22.12.0 || ^24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.29.0 || ^8.0.0-rc.1", + "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", + "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", + "rolldown": "^1.0.0-rc.5", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@babel/plugin-transform-runtime": { + "optional": true + }, + "@babel/runtime": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.12", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", + "integrity": "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001782", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz", + "integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.329", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz", + "integrity": "sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", + "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", + "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.4" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", + "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.122.0", + "@rolldown/pluginutils": "1.0.0-rc.12" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.12", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", + "@rolldown/binding-darwin-x64": "1.0.0-rc.12", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz", + "integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.3.tgz", + "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.8", + "rolldown": "1.0.0-rc.12", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/test/my-app/package.json b/test/my-app/package.json new file mode 100644 index 00000000..1df23585 --- /dev/null +++ b/test/my-app/package.json @@ -0,0 +1,30 @@ +{ + "name": "my-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@babel/core": "^7.29.0", + "@eslint/js": "^9.39.4", + "@rolldown/plugin-babel": "^0.2.1", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "babel-plugin-react-compiler": "^1.0.0", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "vite": "^8.0.1" + } +} diff --git a/test/my-app/public/favicon.svg b/test/my-app/public/favicon.svg new file mode 100644 index 00000000..6893eb13 --- /dev/null +++ b/test/my-app/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/my-app/public/icons.svg b/test/my-app/public/icons.svg new file mode 100644 index 00000000..e9522193 --- /dev/null +++ b/test/my-app/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/my-app/src/App.css b/test/my-app/src/App.css new file mode 100644 index 00000000..f90339d8 --- /dev/null +++ b/test/my-app/src/App.css @@ -0,0 +1,184 @@ +.counter { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--accent); + background: var(--accent-bg); + border: 2px solid transparent; + transition: border-color 0.3s; + margin-bottom: 24px; + + &:hover { + border-color: var(--accent-border); + } + &:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) + scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) + scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + & > div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx new file mode 100644 index 00000000..ceeb543d --- /dev/null +++ b/test/my-app/src/App.jsx @@ -0,0 +1,157 @@ +import React from "react"; +import { + LatestDataWidget, + anedyaClientInit, + ChartWidget, + LatestDataGauge, +} from "../../../src/index"; + +function App() { +const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; +const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; +const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; + const client = anedyaClientInit(tokenId, token); +//default min and max +//client ki implementatrion bahar lelo + + //019f5f58-2a58-733e-81cc-fbec233a9856 + //wss://ZxBpErVPCj.acs-r1.ap-in-1.anedya.io/v1/streams/connect + + const currentTime = Date.now(); // ms timestamp +const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp + + return ( +
+

Test Widget SDK

+
+
+ +
+ + {/*
+ { + return { + text: `${value}`, + unitText: unit, + position: "right", // "left" | "right" | "top" | "bottom" + unitStyle: "subscript", // "normal" | "subscript" | "superscript" + }; + }} + onStyleChange={(value) => { + if (value > 80) { + return { + value: { color: "black" }, + label: { color: "orange" }, + }; + } + + return {}; // keep original styling + }} + /> +
+ +
+ { + if (value > 80) { + return { + value: { color: "red" }, + label: { color: "orange" }, + }; + } + + return {}; // keep original styling + }} + /> +
*/} +
+
+ ); +} + +export default App; + + +//create react app +//link public-widget-sdk +//npm run dev +//send this file tp yash to copy paste \ No newline at end of file diff --git a/test/my-app/src/assets/hero.png b/test/my-app/src/assets/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..cc51a3d20ad4bc961b596a6adfd686685cd84bb0 GIT binary patch literal 44919 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 JPDHLkV1myZcL)Fg literal 0 HcmV?d00001 diff --git a/test/my-app/src/assets/react.svg b/test/my-app/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/test/my-app/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/my-app/src/assets/vite.svg b/test/my-app/src/assets/vite.svg new file mode 100644 index 00000000..5101b674 --- /dev/null +++ b/test/my-app/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/test/my-app/src/index.css b/test/my-app/src/index.css new file mode 100644 index 00000000..2c84af06 --- /dev/null +++ b/test/my-app/src/index.css @@ -0,0 +1,111 @@ +:root { + --text: #6b6375; + --text-h: #08060d; + --bg: #fff; + --border: #e5e4e7; + --code-bg: #f4f3ec; + --accent: #aa3bff; + --accent-bg: rgba(170, 59, 255, 0.1); + --accent-border: rgba(170, 59, 255, 0.5); + --social-bg: rgba(244, 243, 236, 0.5); + --shadow: + rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; + + --sans: system-ui, 'Segoe UI', Roboto, sans-serif; + --heading: system-ui, 'Segoe UI', Roboto, sans-serif; + --mono: ui-monospace, Consolas, monospace; + + font: 18px/145% var(--sans); + letter-spacing: 0.18px; + color-scheme: light dark; + color: var(--text); + background: var(--bg); + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + @media (max-width: 1024px) { + font-size: 16px; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --text: #9ca3af; + --text-h: #f3f4f6; + --bg: #16171d; + --border: #2e303a; + --code-bg: #1f2028; + --accent: #c084fc; + --accent-bg: rgba(192, 132, 252, 0.15); + --accent-border: rgba(192, 132, 252, 0.5); + --social-bg: rgba(47, 48, 58, 0.5); + --shadow: + rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; + } + + #social .button-icon { + filter: invert(1) brightness(2); + } +} + +body { + margin: 0; +} + +#root { + width: 1126px; + max-width: 100%; + margin: 0 auto; + text-align: center; + border-inline: 1px solid var(--border); + min-height: 100svh; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +h1, +h2 { + font-family: var(--heading); + font-weight: 500; + color: var(--text-h); +} + +h1 { + font-size: 56px; + letter-spacing: -1.68px; + margin: 32px 0; + @media (max-width: 1024px) { + font-size: 36px; + margin: 20px 0; + } +} +h2 { + font-size: 24px; + line-height: 118%; + letter-spacing: -0.24px; + margin: 0 0 8px; + @media (max-width: 1024px) { + font-size: 20px; + } +} +p { + margin: 0; +} + +code, +.counter { + font-family: var(--mono); + display: inline-flex; + border-radius: 4px; + color: var(--text-h); +} + +code { + font-size: 15px; + line-height: 135%; + padding: 4px 8px; + background: var(--code-bg); +} diff --git a/test/my-app/src/main.jsx b/test/my-app/src/main.jsx new file mode 100644 index 00000000..b9a1a6de --- /dev/null +++ b/test/my-app/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/test/my-app/vite.config.js b/test/my-app/vite.config.js new file mode 100644 index 00000000..19471f13 --- /dev/null +++ b/test/my-app/vite.config.js @@ -0,0 +1,15 @@ +import { defineConfig } from 'vite' +import react, { reactCompilerPreset } from '@vitejs/plugin-react' +import babel from '@rolldown/plugin-babel' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react(), + babel({ presets: [reactCompilerPreset()] }) + ], + resolve: { + dedupe: ["react", "react-dom", "@base-ui/react"], + }, + +}) diff --git a/ts.config.json b/ts.config.json new file mode 100644 index 00000000..a2224bc5 --- /dev/null +++ b/ts.config.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "noEmit": true + }, + "include": ["src"] +} \ No newline at end of file diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 00000000..817804f4 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: true, + external: ["react", "react-dom", "@base-ui/react"], + clean: true, +}); \ No newline at end of file From 2cfdc7f75d5acc504024d9e5747a61945b14b63e Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 14 Jul 2026 16:42:40 +0530 Subject: [PATCH 13/66] commit --- examples/application-example.js | 29 +++++++++++------------------ test/my-app/src/App.jsx | 6 +++--- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/examples/application-example.js b/examples/application-example.js index a274ea66..d66193a3 100644 --- a/examples/application-example.js +++ b/examples/application-example.js @@ -12,12 +12,11 @@ function App() { const token = ""; const client = anedyaClientInit(tokenId, token); - - const currentTime = Date.now(); // ms timestamp -const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp + const currentTime = Date.now(); // ms timestamp + const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp return ( -
`${new Date(d.timestamp * 1000)} : ${d.value} Celsius` } - - onStyleChange={(data) => { - - return { - title: { color: "red" }, - container: { - - background: "rgba(232, 236, 240, 1)", - borderRadius: 10, - - }, - }; - + onStyleChange={(data) => { + return { + title: { color: "red" }, + container: { + background: "rgba(232, 236, 240, 1)", + borderRadius: 10, + }, + }; }} />
@@ -107,7 +101,6 @@ const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp variable="humidity" title="Humidity Sensor" unit={"Β°C"} - styles={{ container: { // width: 350, diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index b4e21112..fc3d7606 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -4,7 +4,7 @@ import { anedyaClientInit, ChartWidget, LatestDataGauge, - StreamWidget + // StreamWidget } from "public-widget-sdk"; // import {StreamWidget} from "public-widget-sdk" @@ -181,7 +181,7 @@ function App() { />
-
-
+
*/}
); From daaa445f3610d21d043ba1d88bc1d75f121e3a12 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 14 Jul 2026 18:20:36 +0530 Subject: [PATCH 14/66] Added a demo bar chart widget --- package-lock.json | 27 +- src/components/Bar Chart/BarChartWidgets.tsx | 626 +++++++++++++++++++ src/components/chartTheme.tsx | 18 + test/my-app/package-lock.json | 37 +- test/my-app/src/App.jsx | 115 +++- 5 files changed, 751 insertions(+), 72 deletions(-) create mode 100644 src/components/Bar Chart/BarChartWidgets.tsx diff --git a/package-lock.json b/package-lock.json index 0ae984ff..b4af1b87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1922,18 +1922,6 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, "node_modules/@typescript/typescript-aix-ppc64": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", @@ -2300,7 +2288,6 @@ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -2407,15 +2394,6 @@ "node": "^14.18.0 || >=16.10.0" } }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", @@ -2879,6 +2857,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -3542,6 +3521,7 @@ "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3552,6 +3532,7 @@ "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3805,6 +3786,7 @@ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -3901,6 +3883,7 @@ "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc" }, diff --git a/src/components/Bar Chart/BarChartWidgets.tsx b/src/components/Bar Chart/BarChartWidgets.tsx new file mode 100644 index 00000000..b06b2123 --- /dev/null +++ b/src/components/Bar Chart/BarChartWidgets.tsx @@ -0,0 +1,626 @@ +import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; +import * as d3 from "d3"; +import { validateRequiredProps } from "../../helpers/validate"; +import { + defaultDateFormatter, + formatDate, + formatNumber, +} from "../../helpers/formatDate"; +import { + ChartStyleSet, + ThemeName, + DEFAULT_THEME, + themes, + mergeStyleSets, + ResponsiveStyleSet, + resolveResponsiveStyle, +} from "../chartTheme"; + +export type { + ChartStyleSet, + ThemeName, + ResponsiveStyleSet, + Breakpoint, +} from "../chartTheme"; +export { + defineStyleRules, + lightTheme, + darkTheme, + themes, + BREAKPOINTS, +} from "../chartTheme"; + +/* ------------------------ Types ------------------------ */ + +export interface BarDataPoint { + name: string; + value: number; +} + +type WidgetState = { + data: BarDataPoint[]; + loading: boolean; + error: string | null; +}; + +type StylesInput = ChartStyleSet | ((state: WidgetState) => ChartStyleSet); + +export interface BarChartWidgetProps { + client?: any; + nodeId?: string; + variable?: string; + from?: number; + to?: number; + limit?: number; + title?: string; + theme?: ThemeName; + styles?: StylesInput; + responsiveStyles?: ResponsiveStyleSet; + tooltipFormat?: (d: BarDataPoint) => string; + // tickCount?: number; + xTickCount?: number | "max"; + yTickCount?: number; + // xTickFormat?: string | ((d: Date) => string); + xTickFormat?: (d: BarDataPoint) => string; + yTickFormat?: string | ((v: number) => string); + onStyleChange?: (data: BarDataPoint[]) => ChartStyleSet | void; + width?: number; + height?: number; + aspectRatio?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + /** + * Minimum width (px) reserved per bar (bar + its gap). If + * `data.length * minBarWidth` would exceed the space actually + * available (container width, or `width` if fixed), the chart + * renders at its natural, larger width and the wrapper becomes + * horizontally scrollable instead of squeezing bars into + * unreadable slivers. Defaults to 32. + */ + minBarWidth?: number; + /** + * TEMP: dummy data source until the real API/client is wired up. + * If omitted and no `client` is provided, `generateDummyData(limit)` + * is used automatically so the widget renders out of the box. + */ + data?: BarDataPoint[]; +} + +const FALLBACK_WIDTH = 800; +const DEFAULT_ASPECT_RATIO = 800 / 500; +const MARGIN = { top: 16, right: 16, bottom: 36, left: 44 }; + +const DEFAULT_MIN_WIDTH = 280; +const DEFAULT_MAX_WIDTH = 1200; +const DEFAULT_MIN_HEIGHT = 200; +const DEFAULT_MAX_HEIGHT = 700; +const DEFAULT_MIN_BAR_WIDTH = 32; + +const clamp = (value: number, min: number, max: number) => + Math.min(Math.max(value, min), max); +const toDateSafe = (ts: number): Date => + ts < 1e12 ? new Date(ts * 1000) : new Date(ts); + +/** TEMP helper β€” swap out once the real API is connected. */ +export function generateDummyData(count = 12): BarDataPoint[] { + return Array.from({ length: count }, (_, i) => ({ + name: `Item ${i + 1}`, + value: Math.round(20 + Math.random() * 80), + })); +} + +/* ------------------------ BarChartWidget ------------------------ */ +export const BarChartWidget: React.FC = ({ + client, + nodeId, + variable, + from, + to, + limit = 12, + title = "Latest Data", + theme = DEFAULT_THEME, + styles = {}, + responsiveStyles, + tooltipFormat, + xTickCount = "max", + yTickCount = 4, + xTickFormat, + yTickFormat, + onStyleChange, + width: fixedWidth, + height: fixedHeight, + aspectRatio = DEFAULT_ASPECT_RATIO, + minWidth = DEFAULT_MIN_WIDTH, + maxWidth = DEFAULT_MAX_WIDTH, + minHeight = DEFAULT_MIN_HEIGHT, + maxHeight = DEFAULT_MAX_HEIGHT, + minBarWidth = DEFAULT_MIN_BAR_WIDTH, + data: dataProp, +}) => { + // client/nodeId/variable/from/to are only required once this widget is + // actually wired to the API. While using dummy/passed-in data, skip the + // validation entirely. + const usingRealClient = !dataProp && !!client; + if (usingRealClient) { + validateRequiredProps( + "Bar Chart Widget", + { client, nodeId, variable, from, to }, + ["client", "nodeId", "variable", "from time", "to time"] + ); + } + + /* ---------------- Responsive sizing (same approach as ChartWidget) ---------------- */ + const containerRef = useRef(null); + const [measuredWidth, setMeasuredWidth] = useState(FALLBACK_WIDTH); + + useLayoutEffect(() => { + if (fixedWidth != null) return; + const el = containerRef.current; + if (!el || typeof ResizeObserver === "undefined") return; + + const observer = new ResizeObserver((entries) => { + const entry = entries[0]; + if (!entry) return; + const w = Math.round(entry.contentRect.width); + if (w > 0) setMeasuredWidth(w); + }); + + observer.observe(el); + return () => observer.disconnect(); + }, [fixedWidth]); + + const availableWidth = fixedWidth ?? clamp(measuredWidth, minWidth, maxWidth); + const effectiveHeight = + fixedHeight ?? + clamp(Math.round(availableWidth / aspectRatio), minHeight, maxHeight); + + /* ---------------- Data (client fetch OR dummy/passed-in) ---------------- */ + const [node, setNode] = useState(null); + const [data, setData] = useState( + dataProp ?? (usingRealClient ? [] : generateDummyData(limit)) + ); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + + useEffect(() => { + if (!usingRealClient) return; + const anedya = client._anedya; + setNode(anedya?.newNode?.(client, nodeId) ?? null); + }, [usingRealClient, client, nodeId]); + + useEffect(() => { + if (dataProp) { + setData(dataProp); + return; + } + if (!usingRealClient || !node) return; + mountedRef.current = true; + + const fetchData = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + + try { + const res = await node.getData({ + variable, + from, + to, + limit, + order: "asc", + }); + if (!mountedRef.current) return; + + if (res.isSuccess && res.isDataAvailable) { + setData(res.data); + } else { + setData([]); + setError(res.error?.errorMessage ?? "No data available"); + } + } catch (err: any) { + if (!mountedRef.current) return; + setData([]); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + + fetchData(); + return () => { + mountedRef.current = false; + }; + }, [dataProp, usingRealClient, node, variable, from, to, limit]); + + /* ---------------- Styling (identical precedence to ChartWidget) ---------------- */ + const [dynamicStyle, setDynamicStyle] = useState({}); + + useEffect(() => { + const fromStylesProp = + typeof styles === "function" ? styles({ data, loading, error }) : styles; + const fromCallback = onStyleChange?.(data) ?? {}; + + setDynamicStyle(mergeStyleSets(fromStylesProp, fromCallback)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data]); + + const resolvedStyle = useMemo( + () => + mergeStyleSets( + { chart: themes[theme] }, + dynamicStyle, + resolveResponsiveStyle(responsiveStyles, availableWidth) + ), + [theme, dynamicStyle, responsiveStyles, availableWidth] + ); + // `barColor`, `barHoverColor`, `barRadius`, `tooltipBg`, `tooltipColor` are + // the new optional tokens added to chartTheme.ts β€” see instructions. + const chartStyle: any = resolvedStyle.chart!; + + /* ---------------- Overflow / scroll logic ---------------- */ + const idealContentWidth = + MARGIN.left + MARGIN.right + Math.max(data.length, 1) * minBarWidth; + const needsScroll = idealContentWidth > availableWidth; + const effectiveWidth = needsScroll ? idealContentWidth : availableWidth; + + const CHART_W = effectiveWidth - MARGIN.left - MARGIN.right; + const CHART_H = effectiveHeight - MARGIN.top - MARGIN.bottom; + + const effectiveXTickCount = + xTickCount === "max" + ? data.length + : effectiveWidth < 380 + ? Math.min(xTickCount, 2) + : effectiveWidth < 560 + ? Math.min(xTickCount, 3) + : xTickCount; + + const { bars, xTicks, yTicks } = useMemo(() => { + if (!data.length) { + return { + bars: [] as { + x: number; + y: number; + w: number; + h: number; + point: BarDataPoint; + }[], + xTicks: [], + yTicks: [], + }; + } + + const x = d3 + .scaleBand() + .domain(data.map((_, i) => i)) + .range([0, CHART_W]) + .padding(0.35); + + const maxY = Math.max(10, d3.max(data, (d) => d.value) ?? 10); + const y = d3.scaleLinear().domain([0, maxY]).nice().range([CHART_H, 0]); + + const bars = data.map((d, i) => ({ + x: x(i) ?? 0, + y: y(d.value), + w: x.bandwidth(), + h: CHART_H - y(d.value), + point: d, + })); + + // Thin out x labels the same way ChartWidget thins ticks, but on + // categorical indices instead of a continuous time scale. + const labelStep = Math.max(1, Math.ceil(data.length / effectiveXTickCount)); + + const xTicks = data + .map((d, i) => ({ i, d })) + .filter(({ i }) => i % labelStep === 0) + .map(({ i, d }) => ({ + x: (x(i) ?? 0) + x.bandwidth() / 2, + label: xTickFormat ? xTickFormat(d) : d.name, + })); + + const yTicks = y.ticks(yTickCount).map((v) => ({ + y: y(v), + label: + typeof yTickFormat === "function" + ? yTickFormat(v) + : typeof yTickFormat === "string" + ? formatNumber(v, yTickFormat) + : String(v), + })); + + return { bars, xTicks, yTicks }; + }, [ + data, + effectiveXTickCount, + yTickCount, + xTickFormat, + yTickFormat, + CHART_W, + CHART_H, + ]); + + /* ---------------- Custom D3-driven tooltip (no Base UI) ---------------- */ + const [hover, setHover] = useState<{ + x: number; + y: number; + point: BarDataPoint; + } | null>(null); + + return ( +
+ {title && ( +

+ {title} +

+ )} + + {loading ? ( +
+
+ +
+ ) : error ? ( +
+
+ {error} +
+
+ ) : data.length === 0 ? ( +
+ No data available +
+ ) : ( + // `overflowX: auto` only kicks in once bars would otherwise be + // squeezed below `minBarWidth` β€” otherwise this behaves exactly + // like ChartWidget's fluid 100%-width svg. +
+ + + {/* X axis */} + + {xTicks.map((t, i) => ( + + {t.label} + + ))} + + {/* Y axis */} + {yTicks.map((t, i) => ( + + {t.label} + + ))} + + {/* X axis */} + + + {/* Y axis */} + + + {bars.map(({ x, y, w, h, point }, i) => { + const isHovered = hover?.point === point; + return ( + + { + const rect = ( + e.currentTarget.ownerSVGElement as SVGSVGElement + ).getBoundingClientRect(); + setHover({ + x: e.clientX - rect.left, + y: e.clientY - rect.top, + point, + }); + }} + onMouseMove={(e) => { + const rect = ( + e.currentTarget.ownerSVGElement as SVGSVGElement + ).getBoundingClientRect(); + setHover({ + x: e.clientX - rect.left, + y: e.clientY - rect.top, + point, + }); + }} + onMouseLeave={() => setHover(null)} + /> + + {point.value} + + + ); + })} + + + + {/* Plain-div tooltip, positioned via the mouse coords captured + above β€” replaces Base UI's Tooltip.* primitives entirely. */} + {hover && ( +
+ {tooltipFormat + ? tooltipFormat(hover.point) + : `${hover.point.name}: ${hover.point.value}`} +
+ )} +
+ )} +
+ ); +}; + +// TODO: swap generateDummyData() usage for real API data once client wiring +// is ready β€” just start passing `client`/`nodeId`/`variable`/`from`/`to` +// (or your own `data` prop) and the dummy fallback stops being used. diff --git a/src/components/chartTheme.tsx b/src/components/chartTheme.tsx index e525d79e..849a2233 100644 --- a/src/components/chartTheme.tsx +++ b/src/components/chartTheme.tsx @@ -22,6 +22,12 @@ export interface ChartColors { tickFontSize: number; /** Font size (px) for the chart title. Exposed so responsiveStyles can shrink it on small screens. */ titleFontSize: number; + + barColor?: string; + barHoverColor?: string; + barRadius?: number; + tooltipBg?: string; + tooltipColor?: string; } /* ============================================================ @@ -63,6 +69,12 @@ export const lightTheme: ChartColors = { titleColor: "#0f172a", tickFontSize: 10, titleFontSize: 16, + + barColor: "#1e88e5", + barHoverColor: "#1565c0", + barRadius: 3, + tooltipBg: "#0f172a", + tooltipColor: "#ffffff", }; export const darkTheme: ChartColors = { @@ -77,6 +89,12 @@ export const darkTheme: ChartColors = { titleColor: "#f1f5f9", tickFontSize: 10, titleFontSize: 16, + + barColor: "#60a5fa", + barHoverColor: "#3b82f6", + barRadius: 3, + tooltipBg: "#1e293b", + tooltipColor: "#f1f5f9", }; export const themes = { diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index 3ae766b8..075ff72b 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -57,6 +57,7 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -266,31 +267,6 @@ "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", - "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", @@ -298,7 +274,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -852,6 +827,7 @@ "integrity": "sha512-q9pE8+47bQNHb5eWVcE6oXppA+JTSwvnrhH53m0ZuHuK5MLvwsLoWrWzBTFQqQ06BVxz1gp0HblLsch8o6pvZw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "picomatch": "^4.0.3" }, @@ -915,6 +891,7 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -961,6 +938,7 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1024,6 +1002,7 @@ "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -1079,6 +1058,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -1268,6 +1248,7 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -2276,6 +2257,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -2308,6 +2290,7 @@ "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/types": "=0.122.0", "@rolldown/pluginutils": "1.0.0-rc.12" @@ -2503,6 +2486,7 @@ "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", @@ -2627,6 +2611,7 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index ceeb543d..5103388d 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -6,33 +6,41 @@ import { LatestDataGauge, } from "../../../src/index"; +import { BarChartWidget } from "../../../src/components/Bar Chart/BarChartWidgets"; + function App() { -const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; -const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; + const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; + const token = + "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; + const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; const client = anedyaClientInit(tokenId, token); -//default min and max -//client ki implementatrion bahar lelo + //default min and max + //client ki implementatrion bahar lelo //019f5f58-2a58-733e-81cc-fbec233a9856 //wss://ZxBpErVPCj.acs-r1.ap-in-1.anedya.io/v1/streams/connect - const currentTime = Date.now(); // ms timestamp -const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp + const currentTime = Date.now(); // ms timestamp + const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp return ( -
-

Test Widget SDK

+

+ Test Widget SDK +

- + +
+ +
+
{/*
Date: Wed, 15 Jul 2026 15:53:58 +0530 Subject: [PATCH 15/66] updated initialization and chart --- README.md | 637 ++++++--------------------- src/components/ChartWidget.tsx | 761 +++++++++++++++++++-------------- src/components/chartTheme.tsx | 313 +++++++------- test/my-app/src/App.jsx | 106 +---- 4 files changed, 738 insertions(+), 1079 deletions(-) diff --git a/README.md b/README.md index 6a0ff65b..2f7cc7ad 100644 --- a/README.md +++ b/README.md @@ -1,571 +1,194 @@ -[PyPI](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk)  [Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js) +# ChartWidget - -

- Logo -

- +A responsive, themeable line chart widget for Anedya data, built on D3 + SVG. -The Anedya Public SDK helps you easily fetch data from Anedya and display it using prebuilt, customizable React widget components. These widgets allow you to quickly visualize IoT data such as latest values and timeseries data. +## Setup -This SDK currently provides: +The widget doesn't create its own SDK client β€” you create it yourself and pass it in: -- [**LatestDataWidget**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latestdatawidget-latestdatawidget) β€” Displays the latest value of a variable. -- [**ChartWidget**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#latest-data-guage-latestdatagauge-) β€” Displays timeseries data between given timestamps. -- [**LatestDataGauge**](https://github.com/anedyaio/anedya-widgets-react/tree/development?tab=readme-ov-file#chart-widget-chartwidget-) β€” A gauge‑style visualization of the latest value. +```jsx +import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; +import { ChartWidget } from "your-sdk"; -# LatestDataWidget `` +const anedya = new Anedya(); +const config = anedya.newConfig(tokenId, token); +const client = anedya.newClient(config); -Displays the latest value of a variable from Anedya. - -## Usage Example - -``` -import { anedyaClientInit } from "../utils/anedyaClient"; -import { LatestDataWidget } from "../components/LatestDataWidget"; - -const client = anedyaClientInit("TOKEN_ID", "TOKEN"); - -function App() { -return ( - { -if (val < 15) return "#3498db"; -if (val < 30) return "#2ecc71"; -return "#e74c3c"; -}} -styles={{ -container: { width: 220, height: 220, bgcolor: "#fafafa" }, -value: { fontWeight: 800 }, -}} + -); -} ``` -βš™οΈ Props +`anedya` and `client` are both required β€” node creation is `anedya.newNode(client, nodeId)`, a method on the top-level SDK instance, not on the client. -| **Prop** | **Type** | **Required** | **Description** | -| ------------------ | ----------------------------------------------- | :----------: | -------------------------------------------------------------------------- | -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | -| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | -| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | -| title | string | ❌ | Optional label displayed above the value. | -| unit | string | ❌ | Unit of measurement shown after the value. | -| styles | StyleSet | ❌ | Custom style overrides for container, label, value, and unit. | -| colorRange | typeof defaultColorRanges | ❌ | Optional custom color range configuration. | -| colorRangeCallback | (value: number, defaultColor: string) => string | ❌ | Callback that lets you overrride the computed color logic for data values. | -| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | +## Required props -🎨 Styling +| Prop | Type | Description | +|---|---|---| +| `anedya` | `any` | The `new Anedya()` instance | +| `client` | `any` | `anedya.newClient(config)` | +| `nodeId` | `string` | Node to fetch from | +| `variable` | `string` | Variable name to chart | +| `from` | `number` | Start timestamp (ms) | +| `to` | `number` | End timestamp (ms) | -The styles prop allows fine-grained control over the look and feel of the widget. +## The styling model -StyleSet Interface +Every stylable part of the chart is a named slot, and every value inside it is **plain CSS** β€” the same properties you'd use in any inline `style` object. Nothing invented, nothing to memorize: -``` -interface StyleSet { -container?: SxProps; -label?: SxProps; -value?: SxProps; -unit?: SxProps; -fontFamily?: string; // Optional global font for all texts +```ts +interface ChartElementStyles { + container?: React.CSSProperties; // outer card β€” border, backgroundColor, width, etc. + title?: React.CSSProperties; + line?: React.CSSProperties; // stroke, strokeWidth + area?: React.CSSProperties; // fill β€” base color for the gradient under the line + dot?: React.CSSProperties & { r?: number }; // fill for color; r for radius (the one non-CSS exception) + axis?: React.CSSProperties; // stroke + tick?: React.CSSProperties; // fill, fontSize } ``` -Default Styles - -``` -const defaultStyles = { -container: { -bgcolor: "#f4f4f4", -borderRadius: 2, -p: 2, -display: "flex", -flexDirection: "column", -justifyContent: "center", -alignItems: "center", -textAlign: "center", -width: 200, -height: 200, -gap: 10, -}, -label: { fontWeight: 500, color: "#666" }, -value: { fontWeight: 700, color: "#333" }, -unit: { fontWeight: 400, color: "#888" }, -}; -``` - -You can override any of these: - -``` - -``` - -🎨 Color Customization - -Use colorRangeCallback to apply dynamic colors based on value: - -``` -colorRangeCallback={(val, def) => { -if (val < 30) return "#2ecc71"; // green -if (val < 70) return "#f1c40f"; // yellow -if (val <= 100) return "#e74c3c"; // red -return def; -}} -``` - -You can also provide your own static colorRange set if you want total control. - -πŸ“Œ LatestData Widget β€” Callback Options - -The LatestData widget supports two optional callbacks that allow you to fully customize how the displayed value and styling behave. - -## 1. displayText Callback (Value + Unit Formatter) - -The displayText callback lets you customize: - -- how the value is displayed +These are spread directly onto the corresponding SVG elements (``, etc.) β€” all standard SVG presentation properties (`fill`, `stroke`, `strokeWidth`, `fontSize`, `opacity`, ...) work as real CSS in every modern browser, so there's no translation layer. -- what unit text should look like +**One exception:** `dot.r` (circle radius) is a plain number, not a CSS property β€” SVG geometry attributes like radius aren't stylable via CSS, only settable directly on the element. -- here the unit is placed +## The `styles` prop β€” everything in one place -- unit formatting style (normal, subscript, superscript) +There's a single `styles` prop. It optionally accepts three *kinds* of keys, all in the same object: -### What This Callback Looks Like +```jsx + { - text: string; - unitText?: string; - position?: "left" | "right" | "top" | "bottom"; - unitStyle?: "normal" | "subscript" | "superscript"; -}; -``` + // 2. THEME keys ("light" / "dark") β€” only apply when that theme is active + dark: { container: { backgroundColor: "#111827" } }, -### Usage Example - -``` - ({ - text: `${value}`, - unitText: unit, - position: "right", // left | right | top | bottom - unitStyle: "normal", // normal | subscript | superscript - })} + // 3. BREAKPOINT keys ("sm" / "md" / "lg" / "xl") β€” only apply once the + // widget's own measured width crosses that threshold + sm: { tick: { fontSize: 8 } }, + lg: { tick: { fontSize: 12 } }, + }} /> ``` -| Property | Type | Description | -| ------------- | ------------------------------------------ | ----------------------------------------------------- | -| **text** | `string` | The formatted value to display | -| **unitText** | `string` | Custom unit text (optional) | -| **position** | `"left" \| "right" \| "top" \| "bottom"` | Where the unit should be placed relative to the value | -| **unitStyle** | `"normal" \| "subscript" \| "superscript"` | Choose how the unit should appear | - -### Examples +`styles` can also be a function of the widget's current state, if styling needs to depend on load/error status rather than just data: -#### Move unit to the top - -``` -displayText={() => ({ text: "25.3", unitText: "Β°C", position: "top" })} +```jsx +styles={(state) => (state.error ? { container: { border: "1px solid red" } } : {})} ``` -#### Show unit as subscript +### Theme defaults +```jsx + // or "light" (default) ``` -displayText={(value) => ({ - text: value.toFixed(1), - unitText: "ppm", - unitStyle: "subscript", -})} -``` - -## 2. onStyleChange Callback (Dynamic Styling) -This callback lets you override widget styling based on live value updates. +`lightTheme` and `darkTheme` (exported from the package) are just `ChartElementStyles` objects with sensible default colors β€” nothing special about them. Setting `theme` picks which one seeds the chart. -It receives the current numeric value and should return partial styles, which will override the base styles. +### Breakpoints -### What This Callback Looks Like +Breakpoints are measured against the **widget's own rendered width** via `ResizeObserver` β€” container-query semantics, not the browser window. This means the chart responds correctly no matter where it's embedded (a sidebar, a dashboard tile, a modal), regardless of how wide the actual browser window is. -``` -onStyleChange?: (value: number) => Partial; -``` +| Breakpoint | Min width | +|---|---| +| `sm` | 640px | +| `md` | 768px | +| `lg` | 1024px | +| `xl` | 1280px | -### Usage Example +Resolution is mobile-first: each breakpoint the container has reached merges on top of smaller ones, same as Tailwind's `sm:`/`md:`/`lg:`/`xl:` prefixes. -``` - { - if (value > 80) { - return { - value: { color: "red", fontWeight: 700 }, - unit: { color: "red" }, - }; - } - - return {}; // keep original styling - }} -/> -``` +## Sizing β€” the same system, not a separate one -### What you can style dynamically +`width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight` are just CSS properties living on `container`. That means sizing goes through the *exact same* flat β†’ theme β†’ breakpoint pipeline as everything else β€” which is what makes the following four cases fall out naturally, with no special-case logic: -You may return overrides for: +```jsx +// Fully fixed β€” no breakpoint overrides anywhere, so it never changes + -| Key | Description | -| ------------ | --------------------------- | -| `container` | Outer wrapper styles | -| `label` | Title text styles | -| `value` | Value text styles | -| `unit` | Unit text styles | -| `fontFamily` | Override global font family | +// Fixed by default, but steps to a new size at a breakpoint (opt-in responsiveness) + -Example returning multiple overrides: +// Fluid β€” continuously follows the container, clamped between bounds + -``` -return { - container: { background: "#ffeeee" }, - value: { color: "#d60000", fontSize: "90px" }, -}; -``` +// Fluid, where the clamp bounds themselves step at a breakpoint + -# Latest Data Guage `` - -Displays a variable's latest data from an Anedya node in a guage - -Usage Example - -```import { anedyaClientInit } from "../utils/anedyaClient"; -import { LatestDataGauge } from "../components/LatestDataWidget"; - -const client = anedyaClientInit("TOKEN_ID", "TOKEN"); - -function App() { -return ( - { - if (value > 80) { - return { - value: { color: "black" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -); -} +// Nothing passed at all β€” fully responsive with built-in defaults +// (clamped between 280–1200px wide, 200–700px tall) + ``` -βš™οΈ Props - -| **Prop** | **Type** | **Required** | **Description** | -| ---------- | ------------------------- | :----------: | ------------------------------------------------------------------------ | -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | -| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | -| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | -| title | string | ❌ | Optional label displayed above the value. | -| unit | string | ❌ | Unit of measurement shown after the value. | -| styles | StyleSet | ❌ | Custom style overrides for container, label, value, and unit. | -| colorRange | typeof defaultColorRanges | ❌ | Optional custom color range configuration. | -| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | - -πŸ“Œ Latest Data Gauge Widget β€” Callback Options - -## 1. onStyleChange Callback (Dynamic Styling) +The `width`/`height`/`minWidth`/`maxWidth`/`minHeight`/`maxHeight` **props** are shorthand for setting these same properties unconditionally on `styles.container` β€” if you also set them explicitly inside `styles`, the `styles` value wins. -This callback lets you override widget styling based on live value updates. +If the container ever gets smaller than the resolved `minWidth`, the chart doesn't get crushed β€” the outer wrapper scrolls horizontally (`overflowX: auto`) instead of squishing the content. -It receives the current numeric value and should return partial styles, which will override the base styles. +## Callbacks β€” data-driven styling -### What This Callback Looks Like +`onStyleChange` runs whenever the fetched data changes, and returns a `ChartElementStyles` object β€” the same flat shape as `styles`: -``` -onStyleChange?: (value: number) => Partial; -``` - -### Usage Example - -``` - { - if (value > 80) { - return { - value: { color: "red", fontWeight: 700 }, - unit: { color: "red" }, - }; - } - - return {}; // keep original styling +```jsx + { + const latest = data[data.length - 1]; + return latest?.value > 80 ? { line: { stroke: "#dc2626" } } : {}; }} /> ``` -### What you can style dynamically - -You may return overrides for: - -| Key | Description | -| ------------ | --------------------------- | -| `container` | Outer wrapper styles | -| `label` | Title text styles | -| `value` | Value text styles | -| `unit` | Unit text styles | -| `fontFamily` | Override global font family | - -Example returning multiple overrides: - -``` -return { - container: { background: "#ffeeee" }, - value: { color: "#d60000", fontSize: "90px" }, -}; -``` - -# Chart Widget `` - -Displays the historical time-series data for a given variable in chart form - -Usage Example - -```import { anedyaClientInit } from "../utils/anedyaClient"; -import { ChartWidget } from "../components/LatestDataWidget"; - -const client = anedyaClientInit("TOKEN_ID", "TOKEN"); - -function App() { -return ( - d.toLocaleDateString()} - yTickFormat={(v) => `${v} Β°C`} - tooltipFormat={(d, unit) => - `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` - } - onStyleChange={(data) => { - return { - title: { color: "red" }, - container: { - background: "rgba(232, 236, 240, 1)", - borderRadius: 10, - }, - }; - }} - /> -); -} -``` - -βš™οΈ Props +`defineStyleRules` is sugar for the common "if a threshold is crossed, change the styling" pattern, so you don't have to hand-write the callback above: -| **Prop** | **Type** | **Required** | **Description** | -| ---------------- | ------------- | :----------: | ----------------------------------------------------------------------------------- | -| client | AnedyaClient | βœ… | An initialized Anedya client instance, created using anedyaClientInit(). | -| nodeId | string | βœ… | ID of the node whose latest data is to be fetched | -| variable | string | βœ… | The variable name (key) to fetch from the node’s data. | -| from | number | βœ… | earliest timestamp or date from which data should be fetched, in milliseconds epoch | -| to | number | βœ… | latest timestamp or date from which data should be fetched, in milliseconds epoch | -| title | string | ❌ | Optional label displayed above the value. | -| fontFamily | string | ❌ | Global font family applied to all text (defaults to "Roboto"). | -| tickCount | number | ❌ | # of X-axis ticks | -| tooltipFormatter | `(p)=>string` | ❌ | Tooltip HTML (p is timestamp in seconds epoch) | -| styles | StyleSet | ❌ | Custom style overrides for container | +```jsx +import { ChartWidget, defineStyleRules } from "your-sdk"; -πŸ“Š Chart Widget β€” Callback Options - -The Chart widget allows you to customize tick labels, tooltip content, and dynamic runtime styles through several optional callbacks. - -## 1. xTickFormat (Format X-Axis Labels) - -Use this to control how X-axis values are displayed. - -### What This Callback Looks Like - -``` -xTickFormat?: (value: number | Date | string) => string; - -``` - -### Example - -``` -xTickFormat={(d) => d.toLocaleDateString()} - -``` - -### Usage - -- Format timestamps - -- Turn raw numbers into readable labels - -- Apply locale-based formats - -## 2. yTickFormat (Format Y-Axis Labels) - -Use this to format numeric Y-axis values. - -### What This Callback Looks Like - -``` -yTickFormat?: (value: number) => string; - -``` - -### Example - -``` -yTickFormat={(v) => `${v} Β°C`} - -``` - -### Usage - -- Add units - -- Round or scale numbers - -- Convert to % or fixed decimals - -## 3. tooltipFormat (Customize Tooltip Text) - -This callback returns the content string used in tooltips when hovering on data points. - -### What This Callback Looks Like - -``` -tooltipFormat?: (dataPoint: ChartDataPoint, unit: string) => string; -``` - -Where ChartDataPoint is typically: - -``` -{ - timestamp: number; - value: number; -} -``` - -### Example - -``` -tooltipFormat={(d, unit) => - `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` -} -``` - -### Usage - -- Format date/time for tooltips - -- Add units, custom labels, or metadata - -- Show multi-line tooltip content - -## 4. onStyleChange (Dynamic Chart Styling) - -This callback allows dynamic runtime style overrides based on the current chart data. - -### What This Callback Looks Like - -``` -onStyleChange?: (data: ChartDataPoint[]) => Partial; + d.value > 80, style: { line: { stroke: "#dc2626" } } }, + { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, + ])} +/> ``` -You can return overrides for any part of the chart: +If multiple rules match, their styles merge in array order (later rules win on overlapping keys), so rules can stack β€” e.g. a broad "warning" rule plus a narrower "critical" rule. -| Key | Description | -| ------------ | --------------------------------- | -| `container` | Wrapper style | -| `title` | Title text | -| `axis` | Axis text & tick style | -| `tooltip` | Tooltip background, color, radius | -| `chart` | Stroke, width, dot radius | -| `fontFamily` | Global font override | +## Full resolution order -### Example - -``` -onStyleChange={(data) => { - return { - title: { color: "red" }, - container: { - background: "rgba(232, 236, 240, 1)", - borderRadius: 10, - }, - }; -}} -``` +Low to high precedence β€” later layers win on any overlapping property: -### Use cases +1. **Theme preset** (`lightTheme` / `darkTheme`) +2. **Sizing shorthand props** (`width`, `minWidth`, etc.) +3. **`styles`' flat keys** +4. **`styles`' active theme key** (`styles.light` or `styles.dark`) +5. **`styles`' active breakpoint keys** (mobile-first cascade) +6. **`onStyleChange` result** β€” always wins, since it's live and data-driven -- Highlight chart when values exceed thresholds +## Other props -- Change themes based on the data +| Prop | Type | Description | +|---|---|---| +| `title` | `string` | Chart title. Default: `"Latest Data"` | +| `limit` | `number` | Max data points fetched. Default: `20` | +| `tickCount` | `number` | X-axis tick count (auto-reduced on narrow containers) | +| `xTickFormat` / `yTickFormat` | `string \| function` | Custom tick label formatting | +| `tooltipFormat` | `(point) => React.ReactNode` | Custom tooltip content β€” can return a string or rich JSX | +| `aspectRatio` | `number` | Width-to-height ratio used to derive height when no fixed/resolved height is set. Default: `1.6` | -- Dim colors when dataset is small +## Known follow-ups -- Respond to live-updating data streams +- Tooltips currently use Base UI (`@base-ui/react/tooltip`); a swap to a D3-based tooltip is planned separately. +- Axis styling currently supports a single stroke color/width, not per-axis-segment overrides. +- No dot-decimation yet on very narrow/dense containers (many points can visually overlap). \ No newline at end of file diff --git a/src/components/ChartWidget.tsx b/src/components/ChartWidget.tsx index e7979aaf..8f9b7f29 100644 --- a/src/components/ChartWidget.tsx +++ b/src/components/ChartWidget.tsx @@ -4,18 +4,20 @@ import { Tooltip } from "@base-ui/react/tooltip"; import { validateRequiredProps } from "../helpers/validate"; import { defaultDateFormatter, formatDate, formatNumber } from "../helpers/formatDate"; import { - ChartStyleSet, + ChartElementStyles, + ChartStyles, ThemeName, DEFAULT_THEME, themes, - mergeStyleSets, - ResponsiveStyleSet, - resolveResponsiveStyle, + mergeElementStyles, + extractFlatStyles, + resolveResponsiveStyles, + Breakpoint, } from "./chartTheme"; // Re-exported so consumers only ever need to import from ChartWidget, // e.g. `import { ChartWidget, defineStyleRules } from "your-sdk"`. -export type { ChartStyleSet, ThemeName, ResponsiveStyleSet, Breakpoint } from "./chartTheme"; +export type { ChartElementStyles, ChartStyles, ThemeName, Breakpoint } from "./chartTheme"; export { defineStyleRules, lightTheme, darkTheme, themes, BREAKPOINTS } from "./chartTheme"; /* ------------------------ Types ------------------------ */ @@ -31,13 +33,30 @@ type WidgetState = { }; // `styles` accepts either a plain object, or a function that receives the -// widget's current state (data/loading/error) and returns a style set β€” -// useful if styling should depend on load state, not just the data values. -// NOTE: this is always UNCONDITIONAL fixed styling β€” same at every screen -// size. Use `responsiveStyles` (below) for per-breakpoint overrides. -type StylesInput = ChartStyleSet | ((state: WidgetState) => ChartStyleSet); +// widget's current state (data/loading/error) and returns a style set. +// The object itself can mix flat keys (unconditional), theme keys +// (light/dark β€” only the active one applies), and breakpoint keys +// (sm/md/lg/xl β€” see the SIZING MODEL note below for how these interact +// with width/height). +type StylesInput = ChartStyles | ((state: WidgetState) => ChartStyles); export interface ChartWidgetProps { + /** + * The Anedya top-level SDK instance, created by the consumer: + * + * const anedya = new Anedya(); + * + * Required (in addition to `client`) because node creation is a method + * on `anedya` itself, not on the client: + * const node = anedya.newNode(client, nodeId); + */ + anedya: any; + /** + * The Anedya client instance, created and configured by the consumer: + * + * const config = anedya.newConfig(tokenId, token); + * const client = anedya.newClient(config); + */ client: any; nodeId: string; variable: string; @@ -45,83 +64,86 @@ export interface ChartWidgetProps { to: number; limit?: number; title?: string; - /** Base color theme. Defaults to "light". Overridden per-token by `styles`, `responsiveStyles`, and `onStyleChange`. */ + /** Base color theme. Defaults to "light". `styles.light`/`styles.dark` can override either theme's specific palette. */ theme?: ThemeName; - /** Fixed styling, unconditional across all screen/container sizes. */ - styles?: StylesInput; /** - * Per-breakpoint styling, layered on top of `styles`. Mobile-first: - * `base` always applies, then `sm`/`md`/`lg`/`xl` apply additionally - * once the widget's own measured container width crosses that - * breakpoint. This measures the widget's OWN box (container-query - * style), not the browser window, so it behaves correctly no matter - * where it's embedded. + * All styling lives here β€” unconditional, per-theme, and per-breakpoint, + * all in one place, all using real CSS property names: * - * responsiveStyles={{ - * base: { chart: { dotRadius: 2, tickFontSize: 8 } }, - * md: { chart: { dotRadius: 3.5, tickFontSize: 10 } }, - * lg: { chart: { dotRadius: 4.5, tickFontSize: 12 } }, + * styles={{ + * line: { stroke: "#7c3aed" }, // always + * dark: { container: { backgroundColor: "#111827" } }, // dark theme only + * lg: { tick: { fontSize: 12 } }, // container >= 1024px * }} + * + * SIZING MODEL (mirrors how MUI's `sx` breakpoint values work): + * `width`/`minWidth`/`maxWidth`/`height`/`minHeight`/`maxHeight` are + * just ordinary CSS properties on `container` β€” so they follow the + * exact same rules as every other style: + * + * - Pass `width` (as a prop, or `styles.container.width`) and define + * NO breakpoint overrides for it β†’ completely fixed, at every + * container size. No responsiveness, by design. + * - Pass `width` AND ALSO override it at a breakpoint + * (`styles.lg.container.width`) β†’ fixed at the base value, then + * steps to the new value once the container reaches that + * breakpoint. Responsiveness only appears because you opted in. + * - Pass `minWidth`/`maxWidth` with no `width` β†’ fluid, continuously + * following the container size, clamped between those bounds + * (this is the default out-of-the-box behavior if you pass no + * sizing at all β€” clamped between sensible built-in defaults). + * - Pass different `minWidth`/`maxWidth` at different breakpoints β†’ + * the fluid envelope itself steps at those breakpoints (e.g. a + * tighter clamp range on mobile, a wider one on desktop). + * + * The `width`/`height`/etc. PROPS below are just shorthand for setting + * `styles.container.width` etc. unconditionally β€” if you also set the + * same property explicitly inside `styles`, the `styles` value wins. */ - responsiveStyles?: ResponsiveStyleSet; - tooltipFormat?: (d: ChartDataPoint) => string; + styles?: StylesInput; + tooltipFormat?: (d: ChartDataPoint) => React.ReactNode; tickCount?: number; xTickFormat?: string | ((d: Date) => string); yTickFormat?: string | ((v: number) => string); /** - * Called with the fetched data whenever it changes. Return a ChartStyleSet - * to override styling conditionally β€” e.g. recolor the line when the - * latest value crosses a threshold. Pair with `defineStyleRules(...)` for - * a declarative shorthand instead of writing this by hand: + * Called with the fetched data whenever it changes. Return a + * ChartElementStyles object (the same flat CSS-property shape as + * `styles`) to override styling conditionally β€” e.g. recolor the line + * when the latest value crosses a threshold. Pair with + * `defineStyleRules(...)` for a declarative shorthand: * * onStyleChange={defineStyleRules([ - * { when: (d) => d.value > 80, style: { chart: { strokeColor: "#dc2626" } } }, - * { when: (d) => d.value < 20, style: { chart: { strokeColor: "#2563eb" } } }, + * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, + * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, * ])} */ - onStyleChange?: (data: ChartDataPoint[]) => ChartStyleSet | void; - /** - * Fixed pixel width. If omitted, the chart is fully RESPONSIVE β€” it - * fills whatever width its parent container gives it, tracked live via - * ResizeObserver. Set this only if you specifically want a non-fluid, - * constant-size chart. - */ + onStyleChange?: (data: ChartDataPoint[]) => ChartElementStyles | void; + /** Shorthand for `styles.container.width` (unconditional, unless you also override it at a breakpoint β€” see the SIZING MODEL note on `styles`). */ width?: number; - /** - * Fixed pixel height. If omitted while `width` is also omitted, height - * is derived from `aspectRatio` relative to the measured container - * width, so the chart keeps sensible proportions at any size. - */ + /** Shorthand for `styles.container.height`. */ height?: number; - /** Width-to-height ratio used to derive height when the chart is responsive (no fixed height given). Defaults to 1.6 (800x500). */ + /** Width-to-height ratio used to derive height when no fixed/resolved height is set anywhere. Defaults to 1.6 (800x500). */ aspectRatio?: number; - /** - * Lower/upper bounds (px) on the RESPONSIVE size β€” ignored entirely if - * `width`/`height` are set to a fixed value, since those already mean - * "constant, don't resize at all." These only kick in for the fluid - * (no fixed width/height) case, so the chart stops shrinking once the - * container gets very small, and stops growing once it gets very large. - * Defaults: minWidth 280, maxWidth 1200, minHeight 200, maxHeight 700. - * Pass your own to override β€” your values always take precedence over - * these defaults. - */ + /** Shorthand for `styles.container.minWidth`. Defaults to 280 if nothing else sets a width. */ minWidth?: number; + /** Shorthand for `styles.container.maxWidth`. Defaults to 1200 if nothing else sets a width. */ maxWidth?: number; + /** Shorthand for `styles.container.minHeight`. Defaults to 200 if nothing else sets a height. */ minHeight?: number; + /** Shorthand for `styles.container.maxHeight`. Defaults to 700 if nothing else sets a height. */ maxHeight?: number; } // Fallback size used only for the very first render, before ResizeObserver // has reported the real container width (e.g. during SSR or the first -// paint frame). Once measured, `measuredWidth` takes over. +// paint frame). Once measured, `availableWidth` takes over. const FALLBACK_WIDTH = 800; const DEFAULT_ASPECT_RATIO = 800 / 500; const MARGIN = { top: 16, right: 16, bottom: 36, left: 44 }; -// Default responsive bounds β€” only used when the chart is fluid (no fixed -// width/height passed) and the caller hasn't supplied their own bounds. -// These exist so the chart can't shrink into an unreadable sliver on a -// tiny screen, or stretch absurdly wide/tall on a huge one. +// Fallback bounds used only when NOTHING anywhere (props or `styles`, at +// any breakpoint) has set minWidth/maxWidth/minHeight/maxHeight β€” i.e. +// true out-of-the-box behavior with zero configuration. const DEFAULT_MIN_WIDTH = 280; const DEFAULT_MAX_WIDTH = 1200; const DEFAULT_MIN_HEIGHT = 200; @@ -129,10 +151,17 @@ const DEFAULT_MAX_HEIGHT = 700; const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max); +// Only trust numeric pixel values for our sizing math. A string CSS value +// (e.g. "50%") is left alone and passed through to the DOM as-is, but +// can't participate in the clamp calculations below. +const asPixelNumber = (v: unknown): number | undefined => + typeof v === "number" && Number.isFinite(v) ? v : undefined; + const toDateSafe = (ts: number): Date => (ts < 1e12 ? new Date(ts * 1000) : new Date(ts)); /* ------------------------ ChartWidget ------------------------ */ export const ChartWidget: React.FC = ({ + anedya, client, nodeId, variable, @@ -142,7 +171,6 @@ export const ChartWidget: React.FC = ({ title = "Latest Data", theme = DEFAULT_THEME, styles = {}, - responsiveStyles, tooltipFormat, tickCount = 4, xTickFormat, @@ -151,33 +179,31 @@ export const ChartWidget: React.FC = ({ width: fixedWidth, height: fixedHeight, aspectRatio = DEFAULT_ASPECT_RATIO, - minWidth = DEFAULT_MIN_WIDTH, - maxWidth = DEFAULT_MAX_WIDTH, - minHeight = DEFAULT_MIN_HEIGHT, - maxHeight = DEFAULT_MAX_HEIGHT, + minWidth: propMinWidth, + maxWidth: propMaxWidth, + minHeight: propMinHeight, + maxHeight: propMaxHeight, }) => { validateRequiredProps( "Chart Widget", - { client, nodeId, variable, from, to }, - ["client", "nodeId", "variable", "from time", "to time"] + { anedya, client, nodeId, variable, from, to }, + ["anedya", "client", "nodeId", "variable", "from", "to"] ); /* ------------------------------------------------------------ - * Responsive sizing - * ------------------------------------------------------------ - * If `fixedWidth` is provided, the chart behaves exactly like - * before (constant pixel size, same on every screen). Otherwise - * we measure the wrapper div's real rendered width via - * ResizeObserver and recompute on every resize β€” so the chart - * genuinely fills whatever space it's given, live, without a - * page reload. + * Measure the TRUE available space (container-query style β€” the + * widget's own box, not the browser window). This always runs, + * regardless of whether sizing looks "fixed": even a fixed width + * might have breakpoint overrides in `styles`, and cosmetic + * (non-sizing) breakpoint styles need to know the current + * breakpoint too. This measurement is intentionally independent + * of whatever we later decide the chart's own rendered size + * should be β€” it's purely "how much room does our parent give us." * ---------------------------------------------------------- */ const containerRef = useRef(null); - const [measuredWidth, setMeasuredWidth] = useState(FALLBACK_WIDTH); + const [availableWidth, setAvailableWidth] = useState(FALLBACK_WIDTH); useLayoutEffect(() => { - // Fixed width means we never need to observe β€” skip entirely. - if (fixedWidth != null) return; const el = containerRef.current; if (!el || typeof ResizeObserver === "undefined") return; @@ -187,46 +213,33 @@ export const ChartWidget: React.FC = ({ const w = Math.round(entry.contentRect.width); // Guard against 0-width flashes (e.g. element briefly display:none) // which would otherwise collapse the chart to nothing. - if (w > 0) setMeasuredWidth(w); + if (w > 0) setAvailableWidth(w); }); observer.observe(el); return () => observer.disconnect(); - }, [fixedWidth]); - - const effectiveWidth = fixedWidth ?? clamp(measuredWidth, minWidth, maxWidth); - const effectiveHeight = - fixedHeight ?? clamp(Math.round(effectiveWidth / aspectRatio), minHeight, maxHeight); - - const CHART_W = effectiveWidth - MARGIN.left - MARGIN.right; - const CHART_H = effectiveHeight - MARGIN.top - MARGIN.bottom; - - // Fewer x-axis ticks on narrow containers so labels don't overlap. - // Only kicks in below the widths where crowding actually becomes a - // problem; larger containers use the caller's requested tickCount as-is. - const effectiveTickCount = - effectiveWidth < 380 ? Math.min(tickCount, 2) : effectiveWidth < 560 ? Math.min(tickCount, 3) : tickCount; + }, []); const [node, setNode] = useState(null); const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - // Holds only the *data-driven* layer of styling (from `styles` prop + - // `onStyleChange`). Theme and responsiveStyles are applied separately - // below so that resizing or switching `theme` never requires waiting - // on the data-fetch effect. - const [dynamicStyle, setDynamicStyle] = useState({}); + // Holds only the *data-driven* layer (onStyleChange result). Everything + // else (theme, shorthand-prop sizing, flat/theme-specific/breakpoint + // `styles`) is resolved separately below so resizing/theme-switching + // never waits on a data-fetch round trip. + const [callbackStyle, setCallbackStyle] = useState({}); const mountedRef = useRef(false); const isFetchingRef = useRef(false); - // Resolve the node through the client's (rate-limited) Anedya instance + // Node creation is a method on the `anedya` instance itself (per the + // SDK docs: `anedya.newNode(client, nodeId)`), not on `client`. useEffect(() => { - if (!client || !nodeId) return; - const anedya = client._anedya; - setNode(anedya?.newNode?.(client, nodeId) ?? null); - }, [client, nodeId]); + if (!anedya || !client || !nodeId) return; + setNode(anedya.newNode?.(client, nodeId) ?? null); + }, [anedya, client, nodeId]); // Fetch data useEffect(() => { @@ -267,37 +280,93 @@ export const ChartWidget: React.FC = ({ }; }, [node, variable, from, to, limit]); - // Resolve the `styles` prop (static or function) and `onStyleChange` - // result whenever the data changes, and merge them together. Order - // matters: onStyleChange is applied last so conditional/threshold - // styling always wins over the caller's static `styles` prop. + // Resolve onStyleChange whenever the data changes. useEffect(() => { - const fromStylesProp = - typeof styles === "function" ? styles({ data, loading, error }) : styles; - const fromCallback = onStyleChange?.(data) ?? {}; - - setDynamicStyle(mergeStyleSets(fromStylesProp, fromCallback)); - // Intentionally only re-resolves when the data itself changes, matching - // the original widget's behavior. + setCallbackStyle(onStyleChange?.(data) ?? {}); // eslint-disable-next-line react-hooks/exhaustive-deps }, [data]); - // Final style resolution, applied in precedence order: - // 1. theme preset (light/dark) β€” base layer - // 2. dynamicStyle (styles prop + onStyleChange) β€” data-driven layer - // 3. responsiveStyles for the current breakpoint β€” highest priority, - // resolved fresh on every render against `effectiveWidth` so a - // live resize is reflected immediately. - const resolvedStyle = useMemo( - () => - mergeStyleSets( - { chart: themes[theme] }, - dynamicStyle, - resolveResponsiveStyle(responsiveStyles, effectiveWidth) - ), - [theme, dynamicStyle, responsiveStyles, effectiveWidth] + // Resolve the static/functional `styles` prop (may depend on + // loading/error/data if passed as a function). + const resolvedStylesInput: ChartStyles = useMemo( + () => (typeof styles === "function" ? styles({ data, loading, error }) : styles), + [styles, data, loading, error] + ); + + // The width/height/min/max PROPS are just shorthand for setting these + // same properties unconditionally on `styles.container` β€” folded in as + // their own layer so `styles.container.xyz`, if also explicitly set, + // still wins (styles is the more explicit API, shorthand props are the + // convenience default). + const propsSizingLayer: ChartElementStyles = useMemo( + () => ({ + container: { + ...(fixedWidth != null && { width: fixedWidth }), + ...(fixedHeight != null && { height: fixedHeight }), + ...(propMinWidth != null && { minWidth: propMinWidth }), + ...(propMaxWidth != null && { maxWidth: propMaxWidth }), + ...(propMinHeight != null && { minHeight: propMinHeight }), + ...(propMaxHeight != null && { maxHeight: propMaxHeight }), + }, + }), + [fixedWidth, fixedHeight, propMinWidth, propMaxWidth, propMinHeight, propMaxHeight] ); - const chartStyle:any = resolvedStyle.chart!; // themes[theme] guarantees every ChartColors field is present + + // Final style resolution, in precedence order (low -> high): + // 1. theme preset (light/dark) + // 2. shorthand sizing props, folded in as container CSS + // 3. flat/unconditional keys from `styles` + // 4. theme-specific keys from `styles` (styles.light or styles.dark) + // 5. breakpoint keys from `styles` (sm/md/lg/xl), resolved against + // `availableWidth` β€” the RAW measured space, not any already- + // clamped/fixed size, so breakpoint selection is never circular + // 6. onStyleChange result β€” always wins, live data-driven + // + // Note this single `resolved` object carries BOTH the cosmetic styling + // (line/dot/axis/tick colors etc.) AND the sizing (container width/ + // min/max) β€” they go through the exact same merge, which is what makes + // "opt into responsiveness by overriding width at a breakpoint" work + // for free, with no separate sizing system. + const resolved = useMemo(() => { + const flat = extractFlatStyles(resolvedStylesInput); + const themeSpecific = resolvedStylesInput[theme] ?? {}; + const responsive = resolveResponsiveStyles(resolvedStylesInput, availableWidth); + + return mergeElementStyles( + themes[theme], + propsSizingLayer, + flat, + themeSpecific, + responsive, + callbackStyle + ); + }, [resolvedStylesInput, theme, propsSizingLayer, availableWidth, callbackStyle]); + + /* ------------------------------------------------------------ + * Derive the chart's actual pixel size from the fully-resolved + * container style. If a numeric width ended up set (from a prop, + * flat styles, or the currently-active breakpoint), that's fixed β€” + * full stop. Otherwise fall back to fluid: clamp the raw available + * width between whatever min/max resolved (falling back to the + * built-in defaults if nothing set them anywhere). + * ---------------------------------------------------------- */ + const resolvedWidth = asPixelNumber(resolved.container?.width); + const resolvedMinWidth = asPixelNumber(resolved.container?.minWidth) ?? DEFAULT_MIN_WIDTH; + const resolvedMaxWidth = asPixelNumber(resolved.container?.maxWidth) ?? DEFAULT_MAX_WIDTH; + const effectiveWidth = resolvedWidth ?? clamp(availableWidth, resolvedMinWidth, resolvedMaxWidth); + + const resolvedHeight = asPixelNumber(resolved.container?.height); + const resolvedMinHeight = asPixelNumber(resolved.container?.minHeight) ?? DEFAULT_MIN_HEIGHT; + const resolvedMaxHeight = asPixelNumber(resolved.container?.maxHeight) ?? DEFAULT_MAX_HEIGHT; + const effectiveHeight = + resolvedHeight ?? clamp(Math.round(effectiveWidth / aspectRatio), resolvedMinHeight, resolvedMaxHeight); + + const CHART_W = effectiveWidth - MARGIN.left - MARGIN.right; + const CHART_H = effectiveHeight - MARGIN.top - MARGIN.bottom; + + // Fewer x-axis ticks on narrow containers so labels don't overlap. + const effectiveTickCount = + effectiveWidth < 380 ? Math.min(tickCount, 2) : effectiveWidth < 560 ? Math.min(tickCount, 3) : tickCount; const { linePath, areaPath, points, xTicks, yTicks } = useMemo(() => { if (!data.length) { @@ -352,220 +421,266 @@ export const ChartWidget: React.FC = ({ }, [data, effectiveTickCount, xTickFormat, yTickFormat, CHART_W, CHART_H]); const gradientId = useMemo(() => `chart-gradient-${Math.random().toString(36).slice(2, 9)}`, []); + const dotRadius = resolved.dot?.r ?? 3.5; + const dotFill = (resolved.dot?.fill as string) ?? "#1e88e5"; + const areaFill = (resolved.area?.fill as string) ?? dotFill; + + // Sizing properties are already accounted for in effectiveWidth/ + // effectiveHeight above β€” strip them out of the container style before + // spreading it onto the div, so we don't set `width` in two places + // (once explicitly as the computed pixel value, once implicitly via + // spread) with potentially different string/number representations. + const { + width: _w, + minWidth: _mnw, + maxWidth: _mxw, + height: _h, + minHeight: _mnh, + maxHeight: _mxh, + ...containerVisualStyle + } = resolved.container ?? {}; return ( - // NOTE ON STYLING APPROACH: this component intentionally uses inline - // styles / SVG presentation attributes instead of Tailwind classes. - // Base UI (used below for the tooltip) is headless and doesn't need - // Tailwind β€” but Tailwind utility classNames shipped from an SDK - // package don't compile in a consuming app's build unless that app's - // Tailwind `content` glob explicitly scans this package, which most - // consumers won't have configured. Inline styles work everywhere with - // zero consumer setup. If Tailwind classes are required, they should - // be pre-compiled into a standalone stylesheet as part of *this SDK's* - // build and shipped as e.g. `dist/style.css` for consumers to import. + // NOTE ON STYLING APPROACH: this component uses inline styles / SVG + // presentation CSS instead of Tailwind classes. Base UI (used below + // for the tooltip) is headless and doesn't need Tailwind β€” but + // Tailwind utility classNames shipped from an SDK package don't + // compile in a consuming app's build unless that app's Tailwind + // `content` glob explicitly scans this package, which most consumers + // won't have configured. Inline styles work everywhere with zero + // consumer setup. + // + // TWO-LAYER STRUCTURE for scroll-on-overflow: + // outer (ref'd, measured by ResizeObserver) β€” fills 100% of + // whatever the true parent gives us, scrolls horizontally if + // content inside is wider than itself. + // inner (the "card") β€” always rendered at its full resolved + // effectiveWidth. If that's wider than the outer wrapper's real + // space, it overflows the outer's box, which (with + // overflowX: auto) becomes a scrollbar instead of squished or + // broken content.
constant pixel size (still capped at 100% so it - // never overflows a parent narrower than the fixed value). - // Fluid -> fills parent, bounded between minWidth/maxWidth. - width: fixedWidth ?? "100%", - maxWidth: fixedWidth != null ? "100%" : `min(100%, ${maxWidth}px)`, - minWidth: fixedWidth != null ? undefined : minWidth, - minHeight: fixedHeight != null ? undefined : minHeight, - maxHeight: fixedHeight != null ? undefined : maxHeight, + width: "100%", + overflowX: "auto", boxSizing: "border-box", - ...resolvedStyle.container, }} > - {title && ( -

- {title} -

- )} - - {loading ? ( -
+
+ {title && ( +

+ {title} +

+ )} + + {loading ? (
- -
- ) : error ? ( -
+ > +
+ +
+ ) : error ? (
- {error} +
+ {error} +
-
- ) : data.length === 0 ? ( -
- No data available -
- ) : ( - // Base UI's Tooltip primitives handle positioning, portaling (so the - // popup escapes SVG clipping), and accessibility (focus/hover/ARIA). - // They apply zero visual styling themselves β€” all the look is defined - // via the `style` props passed to Tooltip.Popup etc. below. - - - - - - - - - - - - - - {/* X axis */} - - {xTicks.map((t, i) => ( - - {t.label} - - ))} - - {/* Y axis */} - {yTicks.map((t, i) => ( - - {t.label} - - ))} - - {points.map(({ cx, cy, point }, i) => ( - - + ) : ( + // Base UI's Tooltip primitives handle positioning, portaling, + // and accessibility only β€” no visual styling of their own. + // (Flagged for a d3-based tooltip swap later, per your note β€” + // left as-is for this pass since it's a separate concern from + // the architectural changes here.) + + + + + + + + + + + + + + {/* X axis */} + + {xTicks.map((t, i) => ( + + {t.label} + + ))} + + {/* Y axis */} + {yTicks.map((t, i) => ( + + {t.label} + + ))} + + {points.map(({ cx, cy, point }, i) => { + const tooltipContent = tooltipFormat + ? tooltipFormat(point) + : `${toDateSafe(point.timestamp).toLocaleString()}: ${point.value}`; + + return ( + + + {/* Native fallback tooltip, works even if the + Base UI popup fails to render for any reason. */} + + {typeof tooltipContent === "string" + ? tooltipContent + : `${toDateSafe(point.timestamp).toLocaleString()}: ${point.value}`} + + {/* Invisible, larger hit target β€” the visible + dot alone is too small to reliably hover. */} + + {/* The visible dot β€” purely decorative. */} + + + } /> - } - /> - - - - {tooltipFormat - ? tooltipFormat(point) - : `${toDateSafe(point.timestamp).toLocaleString()}: ${point.value}`} - - - - - ))} - - - - )} + + + + {tooltipContent} + + + + + ); + })} + + + + )} +
); }; -// TODO: axis-specific style overrides, per-element font family cascade, -// dot-decimation on very narrow/dense containers. \ No newline at end of file +// TODO: swap Base UI tooltip for a d3-based one. Also: +// axis-specific style overrides beyond a single stroke, dot-decimation +// on very narrow/dense containers. \ No newline at end of file diff --git a/src/components/chartTheme.tsx b/src/components/chartTheme.tsx index e525d79e..2d776332 100644 --- a/src/components/chartTheme.tsx +++ b/src/components/chartTheme.tsx @@ -1,222 +1,221 @@ import type { ChartDataPoint } from "./ChartWidget"; /* ============================================================ - * ChartColors + * ChartElementStyles * ------------------------------------------------------------ - * Every color/visual token the chart actually renders with. - * This is intentionally a flat object of *required* fields so - * that `themes.light` / `themes.dark` are guaranteed complete β€” - * no risk of an undefined color slipping through at render time. + * Every stylable part of the chart, each taking REAL CSS + * properties (the same ones you'd use in any inline `style` + * object) instead of invented names. This is the "just like + * inline styling" shape your boss asked for β€” no new vocabulary + * to learn: `stroke`, `fill`, `strokeWidth`, `fontSize`, `color`, + * `border`, `backgroundColor`, etc. all work exactly as they do + * anywhere else in React. + * + * All standard SVG presentation properties (fill, stroke, + * strokeWidth, fontSize, opacity, ...) are valid inside a plain + * `style` object on an SVG element in every modern browser β€” so + * these get spread directly onto the corresponding // + * elements with no translation layer. + * + * The one exception is `dot.r` (circle radius): SVG geometry + * properties like radius aren't stylable via CSS, only settable + * as an element attribute β€” so it's a plain number, not part of + * CSSProperties. * ============================================================ */ -export interface ChartColors { - strokeColor: string; - strokeWidth: number; - gradientColors: [string, string]; - dotRadius: number; - axisColor: string; - tickColor: string; - backgroundColor: string; - borderColor: string; - titleColor: string; - /** Font size (px) for axis tick labels. Exposed so responsiveStyles can shrink it on small screens. */ - tickFontSize: number; - /** Font size (px) for the chart title. Exposed so responsiveStyles can shrink it on small screens. */ - titleFontSize: number; +export interface ChartElementStyles { + /** The outer card wrapper. */ + container?: React.CSSProperties; + /** The chart title text. */ + title?: React.CSSProperties; + /** The line stroke itself. Use `stroke` and `strokeWidth`. */ + line?: React.CSSProperties; + /** The filled area under the line. Use `fill` for the gradient's base color. */ + area?: React.CSSProperties; + /** Data point markers. Use `fill` for color; `r` for radius (plain number, not stylable via CSS). */ + dot?: React.CSSProperties & { r?: number }; + /** The x-axis baseline. Use `stroke`. */ + axis?: React.CSSProperties; + /** Axis tick labels. Use `fill` for color, `fontSize` for size. */ + tick?: React.CSSProperties; } +const ELEMENT_KEYS = [ + "container", + "title", + "line", + "area", + "dot", + "axis", + "tick", +] as const; + /* ============================================================ - * ChartStyleSet + * Breakpoints & themes * ------------------------------------------------------------ - * This is the shape every styling entry point accepts: - * - the `styles` prop (static or a function of widget state) - * - the return value of `onStyleChange` - * - each `style` inside a `defineStyleRules` rule + * Container-width breakpoints (measured via ResizeObserver on + * the widget's own box β€” container-query semantics, not + * viewport/media-query semantics), matching Tailwind's default + * thresholds so the mental model transfers directly. + * ============================================================ */ +export type Breakpoint = "sm" | "md" | "lg" | "xl"; + +export const BREAKPOINTS: Record = { + sm: 640, + md: 768, + lg: 1024, + xl: 1280, +}; + +export type ThemeName = "light" | "dark"; +export const DEFAULT_THEME: ThemeName = "light"; + +/* ============================================================ + * ChartStyles β€” the full shape of the `styles` prop + * ------------------------------------------------------------ + * ONE prop carries everything: unconditional styling (the flat + * keys), per-theme overrides (`light`/`dark`), and per-breakpoint + * overrides (`sm`/`md`/`lg`/`xl`) β€” all optional, all composable. + * There's no separate "responsiveStyles" prop; responsiveness is + * just additional keys on this same object. + * + * styles={{ + * // flat keys: apply unconditionally, at every theme/size + * line: { stroke: "#7c3aed" }, + * + * // theme-specific: only applies when that theme is active + * dark: { container: { backgroundColor: "#111827" } }, * - * `chart` is `Partial` because callers should be - * able to override just one or two tokens (e.g. only strokeColor - * when a threshold is crossed) without having to restate every - * other color. + * // breakpoint-specific: only applies once the widget's + * // measured width crosses that threshold (mobile-first β€” + * // each larger breakpoint layers on top of smaller ones) + * sm: { tick: { fontSize: 8 } }, + * lg: { tick: { fontSize: 12 } }, + * }} * ============================================================ */ -export interface ChartStyleSet { - container?: React.CSSProperties; - title?: React.CSSProperties; - chart?: Partial; -} +export type ChartStyles = ChartElementStyles & + Partial> & + Partial>; /* ============================================================ * Theme presets * ------------------------------------------------------------ - * These are the *base layer* of styling β€” applied before the - * user's `styles` prop and before any `onStyleChange` result. - * Add more presets here (e.g. "minimal") as needed; just make - * sure they satisfy ChartColors fully. + * The base layer, selected via the `theme` prop. Every value is + * plain CSS, so overriding any single token from `styles` is a + * one-line change β€” no custom shape to match. * ============================================================ */ -export const lightTheme: ChartColors = { - strokeColor: "#1e88e5", - strokeWidth: 2, - gradientColors: ["#1e88e5", "#90caf9"], - dotRadius: 3.5, - axisColor: "#cbd5e1", - tickColor: "#64748b", - backgroundColor: "#f8fafc", - borderColor: "#e2e8f0", - titleColor: "#0f172a", - tickFontSize: 10, - titleFontSize: 16, +export const lightTheme: ChartElementStyles = { + container: { border: "1px solid #e2e8f0", backgroundColor: "#f8fafc" }, + title: { color: "#0f172a", fontSize: 16, fontWeight: 600 }, + line: { stroke: "#1e88e5", strokeWidth: 2 }, + area: { fill: "#1e88e5" }, + dot: { fill: "#1e88e5", r: 3.5 }, + axis: { stroke: "#cbd5e1" }, + tick: { fill: "#64748b", fontSize: 10 }, }; -export const darkTheme: ChartColors = { - strokeColor: "#60a5fa", - strokeWidth: 2, - gradientColors: ["#60a5fa", "#1e3a8a"], - dotRadius: 3.5, - axisColor: "#334155", - tickColor: "#94a3b8", - backgroundColor: "#0f172a", - borderColor: "#1e293b", - titleColor: "#f1f5f9", - tickFontSize: 10, - titleFontSize: 16, +export const darkTheme: ChartElementStyles = { + container: { border: "1px solid #1e293b", backgroundColor: "#0f172a" }, + title: { color: "#f1f5f9", fontSize: 16, fontWeight: 600 }, + line: { stroke: "#60a5fa", strokeWidth: 2 }, + area: { fill: "#60a5fa" }, + dot: { fill: "#60a5fa", r: 3.5 }, + axis: { stroke: "#334155" }, + tick: { fill: "#94a3b8", fontSize: 10 }, }; -export const themes = { +export const themes: Record = { light: lightTheme, dark: darkTheme, -} as const; - -export type ThemeName = keyof typeof themes; - -/** Default theme for every ChartWidget instance unless overridden via the `theme` prop. */ -export const DEFAULT_THEME: ThemeName = "light"; +}; /* ============================================================ - * mergeStyleSets + * mergeElementStyles * ------------------------------------------------------------ - * Combines any number of ChartStyleSet objects, left to right, - * where later sets win. Each of container/title/chart is merged - * independently (shallow per-key), so passing only - * `{ chart: { strokeColor: "red" } }` never wipes out the other - * chart tokens that came from an earlier layer (e.g. the theme). - * - * Overall precedence used by ChartWidget (lowest to highest): - * 1. theme preset (light/dark) - * 2. `styles` prop (static object or function of widget state) - * 3. `onStyleChange` result (re-evaluated whenever data changes) + * Combines any number of ChartElementStyles, left to right, + * later sets winning per-key within each part. Because every + * part is now just a plain CSSProperties object, merging is a + * simple per-part spread β€” no custom-shape bookkeeping needed. * ============================================================ */ -export function mergeStyleSets( - ...sets: (ChartStyleSet | undefined | null)[] -): ChartStyleSet { - const result: ChartStyleSet = {}; +export function mergeElementStyles( + ...sets: (ChartElementStyles | undefined | null)[] +): ChartElementStyles { + const result: ChartElementStyles = {}; for (const set of sets) { if (!set) continue; - result.container = { ...result.container, ...set.container }; - result.title = { ...result.title, ...set.title }; - result.chart = { ...result.chart, ...set.chart }; + for (const key of ELEMENT_KEYS) { + if (set[key]) { + result[key] = { ...result[key], ...set[key] } as any; + } + } } return result; } -/* ============================================================ - * Responsive breakpoints - * ------------------------------------------------------------ - * These are CONTAINER-width breakpoints (measured via - * ResizeObserver on the widget's own wrapper), not viewport/ - * window breakpoints β€” matching CSS container-query semantics - * rather than media-query semantics. That's the right behavior - * for an embeddable widget: it should adapt to the box it's - * placed in (a sidebar, a dashboard tile, a modal), not to the - * size of the browser window, which may be much larger than the - * space actually given to the widget. - * - * Thresholds mirror Tailwind's default breakpoints so the mental - * model transfers directly for anyone used to Tailwind's - * sm:/md:/lg:/xl: prefixes. - * ============================================================ */ -export type Breakpoint = "sm" | "md" | "lg" | "xl"; - -export const BREAKPOINTS: Record = { - sm: 640, - md: 768, - lg: 1024, - xl: 1280, -}; - /** - * Responsive style map. `base` always applies; each named - * breakpoint applies *in addition*, once the container's - * measured width is >= that breakpoint's threshold β€” mobile - * first, same cascade model as Tailwind's responsive prefixes. - * - * This is a SEPARATE prop from `styles` on purpose: `styles` - * (or a static object) is unconditional fixed styling that - * applies identically at every screen size, while - * `responsiveStyles` is only ever consulted per-breakpoint. - * Passing one doesn't affect how the other behaves. + * Pulls out just the unconditional/flat part of a ChartStyles + * object β€” i.e. everything EXCEPT the theme-name and breakpoint + * keys. This is what applies regardless of active theme or size. */ -export type ResponsiveStyleSet = Partial>; +export function extractFlatStyles(styles: ChartStyles): ChartElementStyles { + const result: ChartElementStyles = {}; + for (const key of ELEMENT_KEYS) { + if (styles[key]) (result as any)[key] = styles[key]; + } + return result; +} /** - * Resolves a ResponsiveStyleSet down to a single flat - * ChartStyleSet for the widget's current measured container - * width. Layers are merged in ascending breakpoint order so - * larger breakpoints override smaller ones on overlapping keys, - * exactly like cascading CSS media queries. + * Resolves the breakpoint-specific layers of a ChartStyles object + * for the widget's current measured width. Mobile-first cascade: + * each breakpoint the container has reached applies on top of + * smaller ones, same model as Tailwind's sm:/md:/lg:/xl: prefixes. */ -export function resolveResponsiveStyle( - responsiveStyles: ResponsiveStyleSet | undefined, +export function resolveResponsiveStyles( + styles: ChartStyles, containerWidth: number -): ChartStyleSet { - if (!responsiveStyles) return {}; - - const layers: ChartStyleSet[] = []; - if (responsiveStyles.base) layers.push(responsiveStyles.base); - +): ChartElementStyles { + const layers: ChartElementStyles[] = []; (Object.keys(BREAKPOINTS) as Breakpoint[]) .sort((a, b) => BREAKPOINTS[a] - BREAKPOINTS[b]) .forEach((bp) => { - if (containerWidth >= BREAKPOINTS[bp] && responsiveStyles[bp]) { - layers.push(responsiveStyles[bp]!); + if (containerWidth >= BREAKPOINTS[bp] && styles[bp]) { + layers.push(styles[bp]!); } }); - - return mergeStyleSets(...layers); + return mergeElementStyles(...layers); } /* ============================================================ * StyleRule / defineStyleRules * ------------------------------------------------------------ - * Sugar for the common "if value crosses some threshold, change - * the styling" pattern, without writing a raw onStyleChange - * callback by hand every time. + * Sugar for "if the latest value crosses a threshold, change the + * styling," without hand-writing a raw onStyleChange callback. + * Returns the same flat ChartElementStyles shape used everywhere + * else, so there's nothing new to learn here either. * - * `when` is evaluated against the *latest* data point (most - * recent value) plus the full data array, in case a rule needs - * more context (e.g. comparing against an average). - * - * If multiple rules match, their styles are merged in array - * order (later matching rules win on overlapping keys) β€” this - * lets you stack rules like "base warning color" + "critical - * override" instead of only ever applying one. - * - * Usage: * onStyleChange={defineStyleRules([ - * { when: (d) => d.value > 80, style: { chart: { strokeColor: "#dc2626" } } }, - * { when: (d) => d.value < 20, style: { chart: { strokeColor: "#2563eb" } } }, + * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, + * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, * ])} + * + * If multiple rules match, their styles are merged in array order + * (later matching rules win on overlapping keys), so rules can be + * stacked (e.g. a broad "warning" rule plus a narrower "critical" + * rule) instead of only ever applying a single match. * ============================================================ */ export interface StyleRule { when: (latest: ChartDataPoint, allData: ChartDataPoint[]) => boolean; - style: ChartStyleSet; + style: ChartElementStyles; } export function defineStyleRules( rules: StyleRule[] -): (data: ChartDataPoint[]) => ChartStyleSet { +): (data: ChartDataPoint[]) => ChartElementStyles { return (data: ChartDataPoint[]) => { const latest = data[data.length - 1]; if (!latest) return {}; const matched = rules.filter((rule) => rule.when(latest, data)); - return mergeStyleSets(...matched.map((rule) => rule.style)); + return mergeElementStyles(...matched.map((rule) => rule.style)); }; } \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index ceeb543d..eac61765 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -1,7 +1,8 @@ import React from "react"; +import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { LatestDataWidget, - anedyaClientInit, + // anedyaClientInit, ChartWidget, LatestDataGauge, } from "../../../src/index"; @@ -10,7 +11,13 @@ function App() { const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; - const client = anedyaClientInit(tokenId, token); + + +const anedya = new Anedya(); +const config = anedya.newConfig(tokenId, token); +const client = anedya.newClient(config); + + // const client = anedyaClientInit(tokenId, token); //default min and max //client ki implementatrion bahar lelo @@ -45,104 +52,19 @@ const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp }} > -
- {/*
- { - return { - text: `${value}`, - unitText: unit, - position: "right", // "left" | "right" | "top" | "bottom" - unitStyle: "subscript", // "normal" | "subscript" | "superscript" - }; - }} - onStyleChange={(value) => { - if (value > 80) { - return { - value: { color: "black" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -
- -
- { - if (value > 80) { - return { - value: { color: "red" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -
*/} +
); From 960b0583bf9b65f63497f85e40b0a54a53671345 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Thu, 16 Jul 2026 09:55:47 +0530 Subject: [PATCH 16/66] simplified callback --- README.md | 29 +++++++++-------- src/components/ChartWidget.tsx | 58 +++++++++++++++++++++++----------- src/components/chartTheme.tsx | 46 +++++++++++++++++++-------- 3 files changed, 86 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 2f7cc7ad..4f7a207a 100644 --- a/README.md +++ b/README.md @@ -139,31 +139,32 @@ If the container ever gets smaller than the resolved `minWidth`, the chart doesn ## Callbacks β€” data-driven styling -`onStyleChange` runs whenever the fetched data changes, and returns a `ChartElementStyles` object β€” the same flat shape as `styles`: +For simple "if a threshold is crossed, change the styling" logic, pass `styleRules` directly β€” no wrapping function needed, the widget evaluates it internally against the latest data point: ```jsx { - const latest = data[data.length - 1]; - return latest?.value > 80 ? { line: { stroke: "#dc2626" } } : {}; - }} + styleRules={[ + { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, + { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, + ]} /> ``` -`defineStyleRules` is sugar for the common "if a threshold is crossed, change the styling" pattern, so you don't have to hand-write the callback above: +If multiple rules match, their styles merge in array order (later rules win on overlapping keys), so rules can stack β€” e.g. a broad "warning" rule plus a narrower "critical" rule. -```jsx -import { ChartWidget, defineStyleRules } from "your-sdk"; +For anything beyond simple threshold matching, `onStyleChange` runs whenever the fetched data changes and returns a `ChartElementStyles` object (the same flat shape as `styles`) for full custom logic: +```jsx d.value > 80, style: { line: { stroke: "#dc2626" } } }, - { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, - ])} + onStyleChange={(data) => { + const latest = data[data.length - 1]; + const avg = data.reduce((sum, d) => sum + d.value, 0) / data.length; + return latest?.value > avg * 1.5 ? { line: { stroke: "#dc2626" } } : {}; + }} /> ``` -If multiple rules match, their styles merge in array order (later rules win on overlapping keys), so rules can stack β€” e.g. a broad "warning" rule plus a narrower "critical" rule. +If both `styleRules` and `onStyleChange` are used together, `styleRules` resolves first and `onStyleChange` applies on top β€” so custom logic can still override a rule if needed. ## Full resolution order @@ -174,7 +175,7 @@ Low to high precedence β€” later layers win on any overlapping property: 3. **`styles`' flat keys** 4. **`styles`' active theme key** (`styles.light` or `styles.dark`) 5. **`styles`' active breakpoint keys** (mobile-first cascade) -6. **`onStyleChange` result** β€” always wins, since it's live and data-driven +6. **`styleRules` + `onStyleChange` result** β€” always wins, since it's live and data-driven (`styleRules` resolves first, `onStyleChange` on top) ## Other props diff --git a/src/components/ChartWidget.tsx b/src/components/ChartWidget.tsx index 8f9b7f29..70d3e74a 100644 --- a/src/components/ChartWidget.tsx +++ b/src/components/ChartWidget.tsx @@ -12,13 +12,15 @@ import { mergeElementStyles, extractFlatStyles, resolveResponsiveStyles, + resolveStyleRules, + StyleRule, Breakpoint, } from "./chartTheme"; // Re-exported so consumers only ever need to import from ChartWidget, -// e.g. `import { ChartWidget, defineStyleRules } from "your-sdk"`. -export type { ChartElementStyles, ChartStyles, ThemeName, Breakpoint } from "./chartTheme"; -export { defineStyleRules, lightTheme, darkTheme, themes, BREAKPOINTS } from "./chartTheme"; +// e.g. `import { ChartWidget } from "your-sdk"`. +export type { ChartElementStyles, ChartStyles, ThemeName, Breakpoint, StyleRule } from "./chartTheme"; +export { lightTheme, darkTheme, themes, BREAKPOINTS, defineStyleRules } from "./chartTheme"; /* ------------------------ Types ------------------------ */ export interface ChartDataPoint { @@ -101,6 +103,22 @@ export interface ChartWidgetProps { * same property explicitly inside `styles`, the `styles` value wins. */ styles?: StylesInput; + /** + * Declarative threshold styling β€” no callback to write. Pass an array + * of rules; the widget checks each one against the latest data point + * and merges the styles of every rule that matches (later rules win + * on overlapping keys, so rules can stack): + * + * styleRules={[ + * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, + * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, + * ]} + * + * This is the recommended way to do "if value crosses X, change the + * styling." Use `onStyleChange` instead only if you need logic beyond + * simple threshold matching. + */ + styleRules?: StyleRule[]; tooltipFormat?: (d: ChartDataPoint) => React.ReactNode; tickCount?: number; xTickFormat?: string | ((d: Date) => string); @@ -108,14 +126,9 @@ export interface ChartWidgetProps { /** * Called with the fetched data whenever it changes. Return a * ChartElementStyles object (the same flat CSS-property shape as - * `styles`) to override styling conditionally β€” e.g. recolor the line - * when the latest value crosses a threshold. Pair with - * `defineStyleRules(...)` for a declarative shorthand: - * - * onStyleChange={defineStyleRules([ - * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, - * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, - * ])} + * `styles`) to override styling conditionally. For simple threshold + * checks, prefer `styleRules` above β€” reach for this only when you + * need arbitrary logic that rules alone can't express. */ onStyleChange?: (data: ChartDataPoint[]) => ChartElementStyles | void; /** Shorthand for `styles.container.width` (unconditional, unless you also override it at a breakpoint β€” see the SIZING MODEL note on `styles`). */ @@ -171,6 +184,7 @@ export const ChartWidget: React.FC = ({ title = "Latest Data", theme = DEFAULT_THEME, styles = {}, + styleRules, tooltipFormat, tickCount = 4, xTickFormat, @@ -225,10 +239,11 @@ export const ChartWidget: React.FC = ({ const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - // Holds only the *data-driven* layer (onStyleChange result). Everything - // else (theme, shorthand-prop sizing, flat/theme-specific/breakpoint - // `styles`) is resolved separately below so resizing/theme-switching - // never waits on a data-fetch round trip. + // Holds only the *data-driven* layer (styleRules + onStyleChange, + // merged). Everything else (theme, shorthand-prop sizing, + // flat/theme-specific/breakpoint `styles`) is resolved separately + // below so resizing/theme-switching never waits on a data-fetch + // round trip. const [callbackStyle, setCallbackStyle] = useState({}); const mountedRef = useRef(false); @@ -280,11 +295,16 @@ export const ChartWidget: React.FC = ({ }; }, [node, variable, from, to, limit]); - // Resolve onStyleChange whenever the data changes. + // Resolve the data-driven layer whenever data changes: styleRules + // first (declarative threshold matching), then onStyleChange on top + // (so arbitrary custom logic can still override a rule if both are + // used together). useEffect(() => { - setCallbackStyle(onStyleChange?.(data) ?? {}); + const fromRules = resolveStyleRules(styleRules, data); + const fromCallback = onStyleChange?.(data) ?? {}; + setCallbackStyle(mergeElementStyles(fromRules, fromCallback)); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data]); + }, [data, styleRules]); // Resolve the static/functional `styles` prop (may depend on // loading/error/data if passed as a function). @@ -681,6 +701,6 @@ export const ChartWidget: React.FC = ({ ); }; -// TODO: swap Base UI tooltip for a d3-based one. Also: +// TODO: swap Base UI tooltip for a d3-based one (per plan). Also: // axis-specific style overrides beyond a single stroke, dot-decimation // on very narrow/dense containers. \ No newline at end of file diff --git a/src/components/chartTheme.tsx b/src/components/chartTheme.tsx index 2d776332..9a1619a7 100644 --- a/src/components/chartTheme.tsx +++ b/src/components/chartTheme.tsx @@ -186,17 +186,17 @@ export function resolveResponsiveStyles( } /* ============================================================ - * StyleRule / defineStyleRules + * StyleRule / resolveStyleRules * ------------------------------------------------------------ - * Sugar for "if the latest value crosses a threshold, change the - * styling," without hand-writing a raw onStyleChange callback. - * Returns the same flat ChartElementStyles shape used everywhere - * else, so there's nothing new to learn here either. + * Declarative "if the latest value crosses a threshold, change + * the styling" rules. Pass these straight to the widget's + * `styleRules` prop β€” no wrapping needed, the widget evaluates + * them internally against the latest data point: * - * onStyleChange={defineStyleRules([ + * styleRules={[ * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, - * ])} + * ]} * * If multiple rules match, their styles are merged in array order * (later matching rules win on overlapping keys), so rules can be @@ -208,14 +208,32 @@ export interface StyleRule { style: ChartElementStyles; } +/** + * Evaluates a set of StyleRules against the latest data point and + * returns the merged style of every rule that matched. This is what + * the widget's `styleRules` prop calls directly β€” no import needed + * on the consumer's side beyond the `StyleRule` type itself. + */ +export function resolveStyleRules( + rules: StyleRule[] | undefined, + data: ChartDataPoint[] +): ChartElementStyles { + if (!rules || !rules.length) return {}; + const latest = data[data.length - 1]; + if (!latest) return {}; + + const matched = rules.filter((rule) => rule.when(latest, data)); + return mergeElementStyles(...matched.map((rule) => rule.style)); +} + +/** + * @deprecated Prefer passing rules directly to the widget's + * `styleRules` prop β€” no wrapping required. This still works and is + * kept for anyone composing rule-based logic into their own custom + * `onStyleChange` callback by hand. + */ export function defineStyleRules( rules: StyleRule[] ): (data: ChartDataPoint[]) => ChartElementStyles { - return (data: ChartDataPoint[]) => { - const latest = data[data.length - 1]; - if (!latest) return {}; - - const matched = rules.filter((rule) => rule.when(latest, data)); - return mergeElementStyles(...matched.map((rule) => rule.style)); - }; + return (data: ChartDataPoint[]) => resolveStyleRules(rules, data); } \ No newline at end of file From 9516f11915a0ce2d1ecbb26c69876676e1d11001 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 17 Jul 2026 17:34:59 +0530 Subject: [PATCH 17/66] added basic structure --- .DS_Store | Bin 6148 -> 6148 bytes README.md | 13 +- examples/README.md | 174 ---- examples/application-example.js | 189 ----- package-lock.json | 23 +- package.json | 4 +- src/common.ts | 50 ++ src/components/CardWidget.tsx | 198 +++++ src/components/ChartWidget.tsx | 706 ---------------- src/components/Gauge/Gauge.tsx | 126 --- .../Gauge/components/GaugeArc/GaugeArc.tsx | 62 -- .../Gauge/components/Gradient/Gradient.tsx | 17 - .../InvertedTriangle/InvertedTriangle.tsx | 23 - .../Gauge/components/Label/Label.tsx | 86 -- .../Gauge/components/Pointer/Pointer.tsx | 90 -- .../Gauge/components/SVGBase/SVGBase.tsx | 10 - .../UnitOfMeasurement/UnitOfMeasurement.tsx | 23 - src/components/Gauge/components/index.ts | 13 - src/components/Gauge/hooks/useGradient.tsx | 18 - src/components/GaugeReference.tsx | 203 ----- src/components/LatestDataGauge.tsx | 799 ------------------ src/components/LatestDataWidget.tsx | 466 ---------- src/components/chartTheme.tsx | 239 ------ src/components/types.ts | 33 - src/hooks/AnedyaFrontendClient.ts | 142 ---- src/hooks/Older.ts | 62 -- src/hooks/renderLatestData.tsx | 86 -- src/hooks/useSafeFetch.ts | 69 -- src/index.css | 43 - src/index.ts | 10 +- src/themes/defaultTheme.ts | 33 + src/themes/theme.ts | 31 - src/types/card.ts | 7 + src/types/root.ts | 34 +- test/my-app/package-lock.json | 739 +++++++++++++++- test/my-app/package.json | 3 + test/my-app/src/App.jsx | 129 +-- test/my-app/src/globals.css | 54 ++ 38 files changed, 1187 insertions(+), 3820 deletions(-) delete mode 100644 examples/README.md delete mode 100644 examples/application-example.js create mode 100644 src/common.ts create mode 100644 src/components/CardWidget.tsx delete mode 100644 src/components/ChartWidget.tsx delete mode 100644 src/components/Gauge/Gauge.tsx delete mode 100644 src/components/Gauge/components/GaugeArc/GaugeArc.tsx delete mode 100644 src/components/Gauge/components/Gradient/Gradient.tsx delete mode 100644 src/components/Gauge/components/InvertedTriangle/InvertedTriangle.tsx delete mode 100644 src/components/Gauge/components/Label/Label.tsx delete mode 100644 src/components/Gauge/components/Pointer/Pointer.tsx delete mode 100644 src/components/Gauge/components/SVGBase/SVGBase.tsx delete mode 100644 src/components/Gauge/components/UnitOfMeasurement/UnitOfMeasurement.tsx delete mode 100644 src/components/Gauge/components/index.ts delete mode 100644 src/components/Gauge/hooks/useGradient.tsx delete mode 100644 src/components/GaugeReference.tsx delete mode 100644 src/components/LatestDataGauge.tsx delete mode 100644 src/components/LatestDataWidget.tsx delete mode 100644 src/components/chartTheme.tsx delete mode 100644 src/components/types.ts delete mode 100644 src/hooks/AnedyaFrontendClient.ts delete mode 100644 src/hooks/Older.ts delete mode 100644 src/hooks/renderLatestData.tsx delete mode 100644 src/hooks/useSafeFetch.ts delete mode 100644 src/index.css create mode 100644 src/themes/defaultTheme.ts delete mode 100644 src/themes/theme.ts create mode 100644 src/types/card.ts create mode 100644 test/my-app/src/globals.css diff --git a/.DS_Store b/.DS_Store index 917693363ce66b5cb742340ab65427630c91ebd1..38e7e2c8ea7a0b6092e0ec96940ec99c082ff781 100644 GIT binary patch delta 67 zcmZoMXfc=|#>B)qF;Q%yo+2a9#(>?7j69QhSgJS6v%X;3STKWWGdl-A2T;joL5}at Vlles)IT(O|k%56_bA-qmW&l&65Ay&3 delta 222 zcmZoMXfc=|#>B!kF;Q%yo+6{b#(>?7iw`g}F$zrPVXCg@U`S=CU`S-hWhh|C0kVs8 z(hY-?^K%Orz(Dmnkit-toA2V1l#`zXlKXx2-0zbG#~rb&OCg|63}R_P2C}6N43jr7 o$!uQ0be?H5I|n}p(Dj=)GJj{D%rD}|!N|bC1ajKu2$40+0Ak`fa{vGU diff --git a/README.md b/README.md index 4f7a207a..609fc81f 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ const config = anedya.newConfig(tokenId, token); const client = anedya.newClient(config); (state.error ? { container: { border: "1px solid red" } } : { ### Breakpoints Breakpoints are measured against the **widget's own rendered width** via `ResizeObserver` β€” container-query semantics, not the browser window. This means the chart responds correctly no matter where it's embedded (a sidebar, a dashboard tile, a modal), regardless of how wide the actual browser window is. - +//take definitrion from user for breakpoints | Breakpoint | Min width | |---|---| | `sm` | 640px | @@ -140,7 +140,7 @@ If the container ever gets smaller than the resolved `minWidth`, the chart doesn ## Callbacks β€” data-driven styling For simple "if a threshold is crossed, change the styling" logic, pass `styleRules` directly β€” no wrapping function needed, the widget evaluates it internally against the latest data point: - +//update this ```jsx React.ReactNode` | Custom tooltip content β€” can return a string or rich JSX | +| `tooltipFormat` | `(point) => React.ReactNode` | Custom tooltip content β€” can return a string or rich JSX | | `aspectRatio` | `number` | Width-to-height ratio used to derive height when no fixed/resolved height is set. Default: `1.6` | ## Known follow-ups - Tooltips currently use Base UI (`@base-ui/react/tooltip`); a swap to a D3-based tooltip is planned separately. - Axis styling currently supports a single stroke color/width, not per-axis-segment overrides. -- No dot-decimation yet on very narrow/dense containers (many points can visually overlap). \ No newline at end of file +- No dot-decimation yet on very narrow/dense containers (many points can visually overlap). + diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 2e922ca5..00000000 --- a/examples/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# Anedya Public SDK β€” Getting Started - -## Overview - -The Anedya Public SDK helps you easily fetch data from Anedya and display it using prebuilt, customizable React widget components. These widgets allow you to quickly visualize IoT data such as latest values and timeseries data. - -This SDK currently provides: - -* **LatestDataWidget** β€” Displays the latest value of a variable. -* **ChartWidget** β€” Displays timeseries data between given timestamps. -* **LatestDataGauge** β€” A gauge‑style visualization of the latest value. - -All widgets require **client**, **nodeId**, and **variable** props. - ---- - -## 1. Set Up Your Project in Anedya Console - -Before using the SDK, you must create a project in the Anedya console. -Follow the official guide here: - -* **Project Setup:** [https://docs.anedya.io/getting-started/](https://docs.anedya.io/getting-started/) - -To send (ingest) data into Anedya: - -* **Submit Data API:** [https://docs.anedya.io/device/api/submitdata/](https://docs.anedya.io/device/api/submitdata/) - ---- - -## 2. Create an Access Token - -To use the SDK, you must generate an access token. There are two ways: - -1. Go to your project dashboard. -2. Navigate to **Access Tokens**. -3. Create a token using the UI. - -### Important - -Once your **token** and **tokenId** are created: -➑️ **Store them somewhere safe** β€” you will need both in your application. - -You will also need the **nodeId** you included in the `nodes` array when creating the token. This is mandatory when using any widget. - ---- - -## 3. Install the SDK - -Run the following command: - -``` -npm install public-sdk -``` - ---- - -## 4. Import the SDK Components - -```javascript -import anedyaClientInit, { LatestDataWidget, ChartWidget, LatestDataGauge } from "public-sdk"; -``` - ---- - -## 5. Initialize the Anedya Client - -```javascript -const client = anedyaClientInit(tokenId, token); -``` - ---- - -## 6. Using Widgets - -All widgets require the following mandatory props: - -* `client` -* `nodeId` -* `variable` - -**Note:** Every variable you fetch must be added to the `variables` array when creating the token. - -### Additional Props for ChartWidget - -* `from` β€” start timestamp (ms) -* `to` β€” end timestamp (ms) - -### Using Current Time and 24 Hours Ago - -If you want your chart to show data from the last 24 hours, you can dynamically generate the timestamps like this: - -```javascript -const currentTime = Date.now(); // Current time in ms -twentyFourHoursAgo = currentTime - 86400 * 1000; // 24 hours ago in ms -``` - -You can then pass these values into the `from` and `to` props: - -```javascript - -``` - -* `from` β€” start timestamp (ms) -* `to` β€” end timestamp (ms) - ---- - -## 7. Example Usage - -```javascript -function App() { - const nodeId = ""; - const tokenId = ""; - const token = ""; - const client = anedyaClientInit(tokenId, token); - - - const currentTime = Date.now(); // ms timestamp -const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp - - - return ( -
-

Test Widget SDK

- -
- - {/* Chart Widget */} -
- -
- - {/* Latest Data Widget */} -
- -
- - {/* Gauge Widget */} -
- -
-
-
- ); -} - -export default App; -``` - ---- - -## You're ready to use the Anedya Public SDK! - -If you need more help, refer to the official Anedya documentation here: [https://docs.anedya.io/](https://docs.anedya.io/) diff --git a/examples/application-example.js b/examples/application-example.js deleted file mode 100644 index f67076b5..00000000 --- a/examples/application-example.js +++ /dev/null @@ -1,189 +0,0 @@ -import React from "react"; -import { - LatestDataComponent, - anedyaClientInit, - ChartWidget, - LatestDataGauge, -} from "public-sdk"; - -function App() { -const tokenId = "itATCNCVamYNmwfdeBumQMwS"; -const token = "Evd8wL35Xt4tNQOXP11YddiRHtM74jqw3JZYuIaPmnWxNozbmnNTUfVaqXmQERV1"; -const nodeId = "20deeee8-f8ae-11ee-9dd8-c3aa61afe2fb"; - const client = anedyaClientInit(tokenId, token); - - - const currentTime = Date.now(); // ms timestamp -const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp - - return ( -
-

Test Widget SDK

-
-
- d.toLocaleDateString()} - yTickFormat={(v) => `${v} Β°C`} - tooltipFormat={(d, unit) => - `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` - } - - onStyleChange={(data) => { - - return { - title: { color: "red" }, - container: { - - background: "rgba(232, 236, 240, 1)", - borderRadius: 10, - - }, - }; - - }} - /> -
- -
- { - return { - text: `${value}`, - unitText: unit, - position: "right", // "left" | "right" | "top" | "bottom" - unitStyle: "subscript", // "normal" | "subscript" | "superscript" - }; - }} - onStyleChange={(value) => { - if (value > 80) { - return { - value: { color: "black" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -
- -
- { - if (value > 80) { - return { - value: { color: "red" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -
-
-
- ); -} - -export default App; diff --git a/package-lock.json b/package-lock.json index ebb5411a..5c554d04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "dependencies": { "@anedyasystems/anedya-frontend-sdk": "^0.1.1", "@types/d3": "^7.4.3", - "d3": "^7.9.0" + "clsx": "^2.1.1", + "d3": "^7.9.0", + "tailwind-merge": "^3.6.0" }, "devDependencies": { "@base-ui/react": "^1.6.0", @@ -2380,6 +2382,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", @@ -3711,6 +3722,16 @@ "node": ">= 6" } }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", diff --git a/package.json b/package.json index 58657ce6..14d655c2 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,9 @@ "dependencies": { "@anedyasystems/anedya-frontend-sdk": "^0.1.1", "@types/d3": "^7.4.3", - "d3": "^7.9.0" + "clsx": "^2.1.1", + "d3": "^7.9.0", + "tailwind-merge": "^3.6.0" }, "peerDependencies": { "@base-ui/react": "^1.0.0", diff --git a/src/common.ts b/src/common.ts new file mode 100644 index 00000000..710790c8 --- /dev/null +++ b/src/common.ts @@ -0,0 +1,50 @@ + +import { BuiltInTheme, CardSlot } from "./types/card"; +import { WidgetTheme } from "./types/root"; + + +/** + * Every widget takes this shape as its base. Widget-specific props + * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * rather than repeating client/node/sizing/theme plumbing per widget. + * + * `node` is required directly (built by the consumer via + * `anedya.newNode(client, nodeId)`) rather than derived internally β€” + * keeps node/rate-limiting construction fully in the consumer's control, + * outside the widget. + */ +export interface AnedyaWidgetBaseProps { + node: any; + client: any; + nodeId: string; + variable: string; + /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ + from?: number; + to?: number; + limit?: number; + title?: string; + +/** + * Optional theme for the widget. + * + * A theme is a reusable collection of classes for the widget's slots. + * It is merged with the widget's built-in defaults, while the + * `classNames` prop is applied afterwards for per-instance overrides. + */ + +theme?: WidgetTheme | BuiltInTheme; + + /** Applied to the widget's outermost element, on top of everything else. */ + className?: string; + style?: React.CSSProperties; + + // Sizing β€” stay as direct props (shorthand for the container's + // width/height), matching the existing ChartWidget convention. + width?: number; + height?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + aspectRatio?: number; +} \ No newline at end of file diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx new file mode 100644 index 00000000..10f58ffc --- /dev/null +++ b/src/components/CardWidget.tsx @@ -0,0 +1,198 @@ +import { useEffect, useMemo, useRef, useState } from "react"; +import clsx from "clsx"; +import { twMerge } from "tailwind-merge"; +import { AnedyaWidgetBaseProps } from "../common"; +import { SlotClassNames, WidgetTheme } from "../types/root"; + +import { CARD_DEFAULT_CLASSES, darkTheme, lightTheme } from "../themes/defaultTheme"; + +export type CardSlot = "container" | "title" | "value" | "unit" | "label"; + +export interface CardWidgetProps extends AnedyaWidgetBaseProps { + unit?: string; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + precision?: number; + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, anything. When a slot ends up + * with a class from here AND/OR a matched `styleRules`/ + * `onStyleChange` result, this widget's own inline theme styling for + * that slot is skipped entirely, so your class(es) have full, + * uncontested control. + */ + classNames?: SlotClassNames; + +} + +const DEFAULT_WIDTH = 240; +const DEFAULT_MIN_WIDTH = 180; +const DEFAULT_MAX_WIDTH = 480; + + +export function CardWidget({ + node, + variable, + title = "Latest Value", + unit, + precision, + formatValue, + labelText, + theme, + classNames = {}, + className, + style, + width, + height, + minWidth = DEFAULT_MIN_WIDTH, + maxWidth = DEFAULT_MAX_WIDTH, +}: CardWidgetProps) { + const [value, setValue] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + + + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + + useEffect(() => { + if (!node) return; + mountedRef.current = true; + + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + + try { + const res = await node.getLatestData(variable); + if (!mountedRef.current) return; + + if (res.isSuccess && res.isDataAvailable) { + setValue(res.data.value); + setTimestamp(res.data.timestamp); + } else { + setValue(null); + setError(res.error?.errorMessage ?? "No data available"); + } + } catch (err: any) { + if (!mountedRef.current) return; + setValue(null); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + +const resolvedTheme: WidgetTheme = + theme === "dark" + ? darkTheme + : theme === "light" + ? lightTheme + : theme ?? lightTheme; + + // Per-slot resolution: + // - className: static `classNames` prop + rule-driven classes, + // combined via clsx then twMerge β€” resolves real Tailwind + // conflicts between the two sources (e.g. a static text color + // class and a rule-matched one) rather than leaving both in the + // DOM with an unpredictable winner based on stylesheet order. + // - style: the theme's default inline style for that slot β€” + // skipped ENTIRELY if any class exists for that slot (from either + // source), so the class has full control. An inline style would + // otherwise silently win over a class regardless of source, since + // that's just how CSS specificity works. +const resolveSlot = (slot: CardSlot) => + twMerge( + CARD_DEFAULT_CLASSES[slot], + resolvedTheme.classNames[slot], + classNames[slot] + ); + + const displayValue = useMemo(() => { + if (value == null) return null; + if (formatValue) return formatValue(value); + if (precision != null) return value.toFixed(precision); + return String(value); + }, [value, precision, formatValue]); + + const displayLabel = useMemo(() => { + if (timestamp == null) return null; + if (labelText) return labelText(timestamp); + const d = timestamp < 1e12 ? new Date(timestamp * 1000) : new Date(timestamp); + return `Updated ${d.toLocaleTimeString()}`; + }, [timestamp, labelText]); + + return ( +
+ + {title} + + + {loading ? ( +
+ +
+ ) : error ? ( + {error} + ) : ( + <> + + {displayValue} + {unit && ( + + {unit} + + )} + + {displayLabel && ( + + {displayLabel} + + )} + + )} +
+ ); +} \ No newline at end of file diff --git a/src/components/ChartWidget.tsx b/src/components/ChartWidget.tsx deleted file mode 100644 index 70d3e74a..00000000 --- a/src/components/ChartWidget.tsx +++ /dev/null @@ -1,706 +0,0 @@ -import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; -import * as d3 from "d3"; -import { Tooltip } from "@base-ui/react/tooltip"; -import { validateRequiredProps } from "../helpers/validate"; -import { defaultDateFormatter, formatDate, formatNumber } from "../helpers/formatDate"; -import { - ChartElementStyles, - ChartStyles, - ThemeName, - DEFAULT_THEME, - themes, - mergeElementStyles, - extractFlatStyles, - resolveResponsiveStyles, - resolveStyleRules, - StyleRule, - Breakpoint, -} from "./chartTheme"; - -// Re-exported so consumers only ever need to import from ChartWidget, -// e.g. `import { ChartWidget } from "your-sdk"`. -export type { ChartElementStyles, ChartStyles, ThemeName, Breakpoint, StyleRule } from "./chartTheme"; -export { lightTheme, darkTheme, themes, BREAKPOINTS, defineStyleRules } from "./chartTheme"; - -/* ------------------------ Types ------------------------ */ -export interface ChartDataPoint { - timestamp: number; - value: number; -} - -type WidgetState = { - data: ChartDataPoint[]; - loading: boolean; - error: string | null; -}; - -// `styles` accepts either a plain object, or a function that receives the -// widget's current state (data/loading/error) and returns a style set. -// The object itself can mix flat keys (unconditional), theme keys -// (light/dark β€” only the active one applies), and breakpoint keys -// (sm/md/lg/xl β€” see the SIZING MODEL note below for how these interact -// with width/height). -type StylesInput = ChartStyles | ((state: WidgetState) => ChartStyles); - -export interface ChartWidgetProps { - /** - * The Anedya top-level SDK instance, created by the consumer: - * - * const anedya = new Anedya(); - * - * Required (in addition to `client`) because node creation is a method - * on `anedya` itself, not on the client: - * const node = anedya.newNode(client, nodeId); - */ - anedya: any; - /** - * The Anedya client instance, created and configured by the consumer: - * - * const config = anedya.newConfig(tokenId, token); - * const client = anedya.newClient(config); - */ - client: any; - nodeId: string; - variable: string; - from: number; - to: number; - limit?: number; - title?: string; - /** Base color theme. Defaults to "light". `styles.light`/`styles.dark` can override either theme's specific palette. */ - theme?: ThemeName; - /** - * All styling lives here β€” unconditional, per-theme, and per-breakpoint, - * all in one place, all using real CSS property names: - * - * styles={{ - * line: { stroke: "#7c3aed" }, // always - * dark: { container: { backgroundColor: "#111827" } }, // dark theme only - * lg: { tick: { fontSize: 12 } }, // container >= 1024px - * }} - * - * SIZING MODEL (mirrors how MUI's `sx` breakpoint values work): - * `width`/`minWidth`/`maxWidth`/`height`/`minHeight`/`maxHeight` are - * just ordinary CSS properties on `container` β€” so they follow the - * exact same rules as every other style: - * - * - Pass `width` (as a prop, or `styles.container.width`) and define - * NO breakpoint overrides for it β†’ completely fixed, at every - * container size. No responsiveness, by design. - * - Pass `width` AND ALSO override it at a breakpoint - * (`styles.lg.container.width`) β†’ fixed at the base value, then - * steps to the new value once the container reaches that - * breakpoint. Responsiveness only appears because you opted in. - * - Pass `minWidth`/`maxWidth` with no `width` β†’ fluid, continuously - * following the container size, clamped between those bounds - * (this is the default out-of-the-box behavior if you pass no - * sizing at all β€” clamped between sensible built-in defaults). - * - Pass different `minWidth`/`maxWidth` at different breakpoints β†’ - * the fluid envelope itself steps at those breakpoints (e.g. a - * tighter clamp range on mobile, a wider one on desktop). - * - * The `width`/`height`/etc. PROPS below are just shorthand for setting - * `styles.container.width` etc. unconditionally β€” if you also set the - * same property explicitly inside `styles`, the `styles` value wins. - */ - styles?: StylesInput; - /** - * Declarative threshold styling β€” no callback to write. Pass an array - * of rules; the widget checks each one against the latest data point - * and merges the styles of every rule that matches (later rules win - * on overlapping keys, so rules can stack): - * - * styleRules={[ - * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, - * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, - * ]} - * - * This is the recommended way to do "if value crosses X, change the - * styling." Use `onStyleChange` instead only if you need logic beyond - * simple threshold matching. - */ - styleRules?: StyleRule[]; - tooltipFormat?: (d: ChartDataPoint) => React.ReactNode; - tickCount?: number; - xTickFormat?: string | ((d: Date) => string); - yTickFormat?: string | ((v: number) => string); - /** - * Called with the fetched data whenever it changes. Return a - * ChartElementStyles object (the same flat CSS-property shape as - * `styles`) to override styling conditionally. For simple threshold - * checks, prefer `styleRules` above β€” reach for this only when you - * need arbitrary logic that rules alone can't express. - */ - onStyleChange?: (data: ChartDataPoint[]) => ChartElementStyles | void; - /** Shorthand for `styles.container.width` (unconditional, unless you also override it at a breakpoint β€” see the SIZING MODEL note on `styles`). */ - width?: number; - /** Shorthand for `styles.container.height`. */ - height?: number; - /** Width-to-height ratio used to derive height when no fixed/resolved height is set anywhere. Defaults to 1.6 (800x500). */ - aspectRatio?: number; - /** Shorthand for `styles.container.minWidth`. Defaults to 280 if nothing else sets a width. */ - minWidth?: number; - /** Shorthand for `styles.container.maxWidth`. Defaults to 1200 if nothing else sets a width. */ - maxWidth?: number; - /** Shorthand for `styles.container.minHeight`. Defaults to 200 if nothing else sets a height. */ - minHeight?: number; - /** Shorthand for `styles.container.maxHeight`. Defaults to 700 if nothing else sets a height. */ - maxHeight?: number; -} - -// Fallback size used only for the very first render, before ResizeObserver -// has reported the real container width (e.g. during SSR or the first -// paint frame). Once measured, `availableWidth` takes over. -const FALLBACK_WIDTH = 800; -const DEFAULT_ASPECT_RATIO = 800 / 500; -const MARGIN = { top: 16, right: 16, bottom: 36, left: 44 }; - -// Fallback bounds used only when NOTHING anywhere (props or `styles`, at -// any breakpoint) has set minWidth/maxWidth/minHeight/maxHeight β€” i.e. -// true out-of-the-box behavior with zero configuration. -const DEFAULT_MIN_WIDTH = 280; -const DEFAULT_MAX_WIDTH = 1200; -const DEFAULT_MIN_HEIGHT = 200; -const DEFAULT_MAX_HEIGHT = 700; - -const clamp = (value: number, min: number, max: number) => Math.min(Math.max(value, min), max); - -// Only trust numeric pixel values for our sizing math. A string CSS value -// (e.g. "50%") is left alone and passed through to the DOM as-is, but -// can't participate in the clamp calculations below. -const asPixelNumber = (v: unknown): number | undefined => - typeof v === "number" && Number.isFinite(v) ? v : undefined; - -const toDateSafe = (ts: number): Date => (ts < 1e12 ? new Date(ts * 1000) : new Date(ts)); - -/* ------------------------ ChartWidget ------------------------ */ -export const ChartWidget: React.FC = ({ - anedya, - client, - nodeId, - variable, - from, - to, - limit = 20, - title = "Latest Data", - theme = DEFAULT_THEME, - styles = {}, - styleRules, - tooltipFormat, - tickCount = 4, - xTickFormat, - yTickFormat, - onStyleChange, - width: fixedWidth, - height: fixedHeight, - aspectRatio = DEFAULT_ASPECT_RATIO, - minWidth: propMinWidth, - maxWidth: propMaxWidth, - minHeight: propMinHeight, - maxHeight: propMaxHeight, -}) => { - validateRequiredProps( - "Chart Widget", - { anedya, client, nodeId, variable, from, to }, - ["anedya", "client", "nodeId", "variable", "from", "to"] - ); - - /* ------------------------------------------------------------ - * Measure the TRUE available space (container-query style β€” the - * widget's own box, not the browser window). This always runs, - * regardless of whether sizing looks "fixed": even a fixed width - * might have breakpoint overrides in `styles`, and cosmetic - * (non-sizing) breakpoint styles need to know the current - * breakpoint too. This measurement is intentionally independent - * of whatever we later decide the chart's own rendered size - * should be β€” it's purely "how much room does our parent give us." - * ---------------------------------------------------------- */ - const containerRef = useRef(null); - const [availableWidth, setAvailableWidth] = useState(FALLBACK_WIDTH); - - useLayoutEffect(() => { - const el = containerRef.current; - if (!el || typeof ResizeObserver === "undefined") return; - - const observer = new ResizeObserver((entries) => { - const entry = entries[0]; - if (!entry) return; - const w = Math.round(entry.contentRect.width); - // Guard against 0-width flashes (e.g. element briefly display:none) - // which would otherwise collapse the chart to nothing. - if (w > 0) setAvailableWidth(w); - }); - - observer.observe(el); - return () => observer.disconnect(); - }, []); - - const [node, setNode] = useState(null); - const [data, setData] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - // Holds only the *data-driven* layer (styleRules + onStyleChange, - // merged). Everything else (theme, shorthand-prop sizing, - // flat/theme-specific/breakpoint `styles`) is resolved separately - // below so resizing/theme-switching never waits on a data-fetch - // round trip. - const [callbackStyle, setCallbackStyle] = useState({}); - - const mountedRef = useRef(false); - const isFetchingRef = useRef(false); - - // Node creation is a method on the `anedya` instance itself (per the - // SDK docs: `anedya.newNode(client, nodeId)`), not on `client`. - useEffect(() => { - if (!anedya || !client || !nodeId) return; - setNode(anedya.newNode?.(client, nodeId) ?? null); - }, [anedya, client, nodeId]); - - // Fetch data - useEffect(() => { - if (!node) return; - mountedRef.current = true; - - const fetchData = async () => { - if (isFetchingRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - - try { - const res = await node.getData({ variable, from, to, limit, order: "asc" }); - if (!mountedRef.current) return; - - if (res.isSuccess && res.isDataAvailable) { - setData(res.data); - } else { - setData([]); - setError(res.error?.errorMessage ?? "No data available"); - } - } catch (err: any) { - if (!mountedRef.current) return; - setData([]); - setError(err?.message ?? "Failed to fetch data"); - } finally { - if (mountedRef.current) { - setLoading(false); - isFetchingRef.current = false; - } - } - }; - - fetchData(); - return () => { - mountedRef.current = false; - }; - }, [node, variable, from, to, limit]); - - // Resolve the data-driven layer whenever data changes: styleRules - // first (declarative threshold matching), then onStyleChange on top - // (so arbitrary custom logic can still override a rule if both are - // used together). - useEffect(() => { - const fromRules = resolveStyleRules(styleRules, data); - const fromCallback = onStyleChange?.(data) ?? {}; - setCallbackStyle(mergeElementStyles(fromRules, fromCallback)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data, styleRules]); - - // Resolve the static/functional `styles` prop (may depend on - // loading/error/data if passed as a function). - const resolvedStylesInput: ChartStyles = useMemo( - () => (typeof styles === "function" ? styles({ data, loading, error }) : styles), - [styles, data, loading, error] - ); - - // The width/height/min/max PROPS are just shorthand for setting these - // same properties unconditionally on `styles.container` β€” folded in as - // their own layer so `styles.container.xyz`, if also explicitly set, - // still wins (styles is the more explicit API, shorthand props are the - // convenience default). - const propsSizingLayer: ChartElementStyles = useMemo( - () => ({ - container: { - ...(fixedWidth != null && { width: fixedWidth }), - ...(fixedHeight != null && { height: fixedHeight }), - ...(propMinWidth != null && { minWidth: propMinWidth }), - ...(propMaxWidth != null && { maxWidth: propMaxWidth }), - ...(propMinHeight != null && { minHeight: propMinHeight }), - ...(propMaxHeight != null && { maxHeight: propMaxHeight }), - }, - }), - [fixedWidth, fixedHeight, propMinWidth, propMaxWidth, propMinHeight, propMaxHeight] - ); - - // Final style resolution, in precedence order (low -> high): - // 1. theme preset (light/dark) - // 2. shorthand sizing props, folded in as container CSS - // 3. flat/unconditional keys from `styles` - // 4. theme-specific keys from `styles` (styles.light or styles.dark) - // 5. breakpoint keys from `styles` (sm/md/lg/xl), resolved against - // `availableWidth` β€” the RAW measured space, not any already- - // clamped/fixed size, so breakpoint selection is never circular - // 6. onStyleChange result β€” always wins, live data-driven - // - // Note this single `resolved` object carries BOTH the cosmetic styling - // (line/dot/axis/tick colors etc.) AND the sizing (container width/ - // min/max) β€” they go through the exact same merge, which is what makes - // "opt into responsiveness by overriding width at a breakpoint" work - // for free, with no separate sizing system. - const resolved = useMemo(() => { - const flat = extractFlatStyles(resolvedStylesInput); - const themeSpecific = resolvedStylesInput[theme] ?? {}; - const responsive = resolveResponsiveStyles(resolvedStylesInput, availableWidth); - - return mergeElementStyles( - themes[theme], - propsSizingLayer, - flat, - themeSpecific, - responsive, - callbackStyle - ); - }, [resolvedStylesInput, theme, propsSizingLayer, availableWidth, callbackStyle]); - - /* ------------------------------------------------------------ - * Derive the chart's actual pixel size from the fully-resolved - * container style. If a numeric width ended up set (from a prop, - * flat styles, or the currently-active breakpoint), that's fixed β€” - * full stop. Otherwise fall back to fluid: clamp the raw available - * width between whatever min/max resolved (falling back to the - * built-in defaults if nothing set them anywhere). - * ---------------------------------------------------------- */ - const resolvedWidth = asPixelNumber(resolved.container?.width); - const resolvedMinWidth = asPixelNumber(resolved.container?.minWidth) ?? DEFAULT_MIN_WIDTH; - const resolvedMaxWidth = asPixelNumber(resolved.container?.maxWidth) ?? DEFAULT_MAX_WIDTH; - const effectiveWidth = resolvedWidth ?? clamp(availableWidth, resolvedMinWidth, resolvedMaxWidth); - - const resolvedHeight = asPixelNumber(resolved.container?.height); - const resolvedMinHeight = asPixelNumber(resolved.container?.minHeight) ?? DEFAULT_MIN_HEIGHT; - const resolvedMaxHeight = asPixelNumber(resolved.container?.maxHeight) ?? DEFAULT_MAX_HEIGHT; - const effectiveHeight = - resolvedHeight ?? clamp(Math.round(effectiveWidth / aspectRatio), resolvedMinHeight, resolvedMaxHeight); - - const CHART_W = effectiveWidth - MARGIN.left - MARGIN.right; - const CHART_H = effectiveHeight - MARGIN.top - MARGIN.bottom; - - // Fewer x-axis ticks on narrow containers so labels don't overlap. - const effectiveTickCount = - effectiveWidth < 380 ? Math.min(tickCount, 2) : effectiveWidth < 560 ? Math.min(tickCount, 3) : tickCount; - - const { linePath, areaPath, points, xTicks, yTicks } = useMemo(() => { - if (!data.length) { - return { linePath: "", areaPath: "", points: [] as { cx: number; cy: number; point: ChartDataPoint }[], xTicks: [], yTicks: [] }; - } - - const dates = data.map((d) => toDateSafe(d.timestamp)); - const x = d3.scaleTime().domain(d3.extent(dates) as [Date, Date]).range([0, CHART_W]); - const maxY = Math.max(10, d3.max(data, (d) => d.value) ?? 10); - const y = d3.scaleLinear().domain([0, maxY]).nice().range([CHART_H, 0]); - - const line = d3 - .line() - .x((d) => x(toDateSafe(d.timestamp))) - .y((d) => y(d.value)) - .curve(d3.curveMonotoneX); - - const area = d3 - .area() - .x((d) => x(toDateSafe(d.timestamp))) - .y0(CHART_H) - .y1((d) => y(d.value)) - .curve(d3.curveMonotoneX); - - const points = data.map((d) => ({ - cx: x(toDateSafe(d.timestamp)), - cy: y(d.value), - point: d, - })); - - const xTicks = x.ticks(effectiveTickCount).map((d) => ({ - x: x(d), - label: - typeof xTickFormat === "function" - ? xTickFormat(d) - : typeof xTickFormat === "string" - ? formatDate(d, xTickFormat) - : defaultDateFormatter(d), - })); - - const yTicks = y.ticks(4).map((v) => ({ - y: y(v), - label: - typeof yTickFormat === "function" - ? yTickFormat(v) - : typeof yTickFormat === "string" - ? formatNumber(v, yTickFormat) - : String(v), - })); - - return { linePath: line(data) ?? "", areaPath: area(data) ?? "", points, xTicks, yTicks }; - }, [data, effectiveTickCount, xTickFormat, yTickFormat, CHART_W, CHART_H]); - - const gradientId = useMemo(() => `chart-gradient-${Math.random().toString(36).slice(2, 9)}`, []); - const dotRadius = resolved.dot?.r ?? 3.5; - const dotFill = (resolved.dot?.fill as string) ?? "#1e88e5"; - const areaFill = (resolved.area?.fill as string) ?? dotFill; - - // Sizing properties are already accounted for in effectiveWidth/ - // effectiveHeight above β€” strip them out of the container style before - // spreading it onto the div, so we don't set `width` in two places - // (once explicitly as the computed pixel value, once implicitly via - // spread) with potentially different string/number representations. - const { - width: _w, - minWidth: _mnw, - maxWidth: _mxw, - height: _h, - minHeight: _mnh, - maxHeight: _mxh, - ...containerVisualStyle - } = resolved.container ?? {}; - - return ( - // NOTE ON STYLING APPROACH: this component uses inline styles / SVG - // presentation CSS instead of Tailwind classes. Base UI (used below - // for the tooltip) is headless and doesn't need Tailwind β€” but - // Tailwind utility classNames shipped from an SDK package don't - // compile in a consuming app's build unless that app's Tailwind - // `content` glob explicitly scans this package, which most consumers - // won't have configured. Inline styles work everywhere with zero - // consumer setup. - // - // TWO-LAYER STRUCTURE for scroll-on-overflow: - // outer (ref'd, measured by ResizeObserver) β€” fills 100% of - // whatever the true parent gives us, scrolls horizontally if - // content inside is wider than itself. - // inner (the "card") β€” always rendered at its full resolved - // effectiveWidth. If that's wider than the outer wrapper's real - // space, it overflows the outer's box, which (with - // overflowX: auto) becomes a scrollbar instead of squished or - // broken content. -
-
- {title && ( -

- {title} -

- )} - - {loading ? ( -
-
- -
- ) : error ? ( -
-
- {error} -
-
- ) : data.length === 0 ? ( -
- No data available -
- ) : ( - // Base UI's Tooltip primitives handle positioning, portaling, - // and accessibility only β€” no visual styling of their own. - // (Flagged for a d3-based tooltip swap later, per your note β€” - // left as-is for this pass since it's a separate concern from - // the architectural changes here.) - - - - - - - - - - - - - - {/* X axis */} - - {xTicks.map((t, i) => ( - - {t.label} - - ))} - - {/* Y axis */} - {yTicks.map((t, i) => ( - - {t.label} - - ))} - - {points.map(({ cx, cy, point }, i) => { - const tooltipContent = tooltipFormat - ? tooltipFormat(point) - : `${toDateSafe(point.timestamp).toLocaleString()}: ${point.value}`; - - return ( - - - {/* Native fallback tooltip, works even if the - Base UI popup fails to render for any reason. */} - - {typeof tooltipContent === "string" - ? tooltipContent - : `${toDateSafe(point.timestamp).toLocaleString()}: ${point.value}`} - - {/* Invisible, larger hit target β€” the visible - dot alone is too small to reliably hover. */} - - {/* The visible dot β€” purely decorative. */} - - - } - /> - - - - {tooltipContent} - - - - - ); - })} - - - - )} -
-
- ); -}; - -// TODO: swap Base UI tooltip for a d3-based one (per plan). Also: -// axis-specific style overrides beyond a single stroke, dot-decimation -// on very narrow/dense containers. \ No newline at end of file diff --git a/src/components/Gauge/Gauge.tsx b/src/components/Gauge/Gauge.tsx deleted file mode 100644 index 40eb68b3..00000000 --- a/src/components/Gauge/Gauge.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import React, { useCallback, useMemo } from "react"; -import { scaleLinear } from "d3"; - -import { - SVGBase, - Pointer, - InvertedTriangle, - UnitOfMeasurement, - GaugeArc, - Label -} from "./components"; - -import "../../index.css" -const defaultSize = 250; - -const Gauge = ({ - height=400, - width=400, - disabled=false, - value = -1, - min = 0, - max = 100, - maxAngle = 135, - minAngle = -135, - tickCount = 5, - arcSegments = [{ min: 0, max: 1, color: "skyblue" }], - labelProps = { - offsetText: -7.5 - }, - uom = "", - uomProps = { - offsetText: -10, - //-7.5 - }, - pointerLabel = "", - ...props -}) => { - const gaugeOrigin = { - x: 140, - y: 140 - }; - - const valueScale = useCallback( - scaleLinear() - .domain([min, max]) - .range([0, 1]), - [min, max] - ); - - /** Value scaled to [0,1] */ - const valueRef = useMemo(() => valueScale(value), [value, valueScale]); - - return ( - <> - - - - - ); -}; - -export default Gauge; diff --git a/src/components/Gauge/components/GaugeArc/GaugeArc.tsx b/src/components/Gauge/components/GaugeArc/GaugeArc.tsx deleted file mode 100644 index 4b8dd5ae..00000000 --- a/src/components/Gauge/components/GaugeArc/GaugeArc.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { PureComponent } from "react"; -import { scaleLinear, lineRadial } from "d3"; - -/** Ratio of arc to size of container. */ -const baseRatio = 0.8; - -/** Resolution of arc. */ -const length = 40; - -class GaugeArc extends PureComponent { - render() { - const { - inset = 0, - min = 0, - max = 1, - maxAngle, - minAngle, - center = { x: 125, y: 135 }, - ...props - }:any = this.props; - - /** Calculate max angle of arc from degrees to radians */ - const maxRatio = maxAngle / 180; - const arcMax = Math.PI * maxRatio; - - /** Calculate min angle of arc from degrees to radians */ - const minRatio = minAngle / 180; - const arcMin = Math.PI * minRatio; - - /** Linear map from [0,1] to [-135,135] degrees in radians */ - const refToRads = scaleLinear() - .domain([0, 1]) - .range([arcMin, arcMax]); - - /** Render scale to map [0,length - 1] to [minAndle, maxAngle] for rendering */ - const arcScale = scaleLinear() - .domain([0, length - 1]) - .range([refToRads(min), refToRads(max)]); - - /** Actual path function to generate path. */ - const arc:any = lineRadial() - .angle((d, i) => arcScale(i)) - .radius((250 * baseRatio) / 2 - inset); - - const arcPath = arc({ length }); - - return ( - - ); - } -} - -export default GaugeArc; diff --git a/src/components/Gauge/components/Gradient/Gradient.tsx b/src/components/Gauge/components/Gradient/Gradient.tsx deleted file mode 100644 index 14ce43e4..00000000 --- a/src/components/Gauge/components/Gradient/Gradient.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React, { PureComponent } from "react"; - -class Gradient extends PureComponent { - render() { - const { start, end, id, disabled }:any = this.props; - return ( - - - - - - - ); - } -} - -export default Gradient; diff --git a/src/components/Gauge/components/InvertedTriangle/InvertedTriangle.tsx b/src/components/Gauge/components/InvertedTriangle/InvertedTriangle.tsx deleted file mode 100644 index cfe844df..00000000 --- a/src/components/Gauge/components/InvertedTriangle/InvertedTriangle.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { PureComponent } from "react"; -import { symbol, symbolTriangle } from "d3"; - -class InvertedTriangle extends PureComponent { - render() { - const { center, disabled }:any = this.props; - return ( - - ); - } -} - -export default InvertedTriangle; diff --git a/src/components/Gauge/components/Label/Label.tsx b/src/components/Gauge/components/Label/Label.tsx deleted file mode 100644 index 2bcb4c5b..00000000 --- a/src/components/Gauge/components/Label/Label.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { PureComponent } from "react"; -import { scaleLinear, line } from "d3"; - -const getTickRef = (tickCount:any, minVal:any, maxVal:any, minAngle:any, maxAngle:any) => { - if (tickCount % 2 === 0) - console.warn( - "Ticks should be odd numbered to ensure a tick in in the middle of the gauge." - ); - - const idxToRef = scaleLinear() - .domain([0, tickCount - 1]) - .range([0, 1]); - - const idxToVal = scaleLinear() - .domain([0, tickCount - 1]) - .range([minVal, maxVal]); - - const refToDeg = scaleLinear() - .domain([0, 1]) - .range([minAngle, maxAngle]); - - return [...Array(tickCount)].map((v, i) => ({ - index: i, - val: idxToVal(i), - deg: refToDeg(idxToRef(i)) - })); -}; - -const tickLineLong = line() - .x(0) - .y((d, i) => i)(Array.from({ length: 35 })); - -const tickLineShort = line() - .x(0) - .y((d, i) => i)(Array.from({ length: 12 })); - -class Label extends PureComponent { - render() { - const { - disabled, - center, - tickCount, - min, - max, - maxAngle, - minAngle, - offsetText, - length = 300 / 2 - 30 - }:any = this.props; - - const ticks = getTickRef(tickCount, min, max, minAngle, maxAngle); - - return ticks.map(({ val, deg, index }) => { - return ( - - - - {Number(val)} - - - ); - }); - } -} - -export default Label; diff --git a/src/components/Gauge/components/Pointer/Pointer.tsx b/src/components/Gauge/components/Pointer/Pointer.tsx deleted file mode 100644 index b64d6eac..00000000 --- a/src/components/Gauge/components/Pointer/Pointer.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import React, { PureComponent } from "react"; -import { line, scaleLinear } from "d3"; - - - -class Pointer extends PureComponent { - render() { - const { - width = 12.5, - head = (0.8 * 250) / 2 - 5, - tail = 5, - value = -5, - tooltip = "", - center = { x: 125, y: 135 }, - minAngle, - maxAngle, - disabled - } :any= this.props; - - const pointerLine = line()([ - [width / 2, 0], - [0, -head], - [-(width / 2), 0], - [0, tail], - [width / 2, 0] - ]); - const valueScale = scaleLinear() - .domain([0, 1]) - .range([minAngle, maxAngle]); - const pointerValue = valueScale(value); - - const showTooltip = (e: React.MouseEvent, text: string) => { - const tooltip = document.getElementById("gauge-tooltip"); - if (!tooltip || !text) return; - - tooltip.textContent = text; - tooltip.style.opacity = "1"; - tooltip.style.transform = "translateY(0px)"; - moveTooltip(e); -}; - -const moveTooltip = (e: React.MouseEvent) => { - const tooltip = document.getElementById("gauge-tooltip"); - if (!tooltip) return; - - tooltip.style.left = e.clientX + 10 + "px"; - tooltip.style.top = e.clientY - 20 + "px"; -}; - -const hideTooltip = () => { - const tooltip = document.getElementById("gauge-tooltip"); - if (!tooltip) return; - - tooltip.style.opacity = "0"; - tooltip.style.transform = "translateY(-5px)"; -}; - - return ( - // - - showTooltip(e, tooltip)} - onMouseMove={(e) => moveTooltip(e)} - onMouseLeave={hideTooltip} - > - {tooltip && {tooltip}} - - - // - ); - } -} - -export default Pointer; diff --git a/src/components/Gauge/components/SVGBase/SVGBase.tsx b/src/components/Gauge/components/SVGBase/SVGBase.tsx deleted file mode 100644 index 565e510b..00000000 --- a/src/components/Gauge/components/SVGBase/SVGBase.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React, { PureComponent, SVGProps } from "react"; - -class SVGBase extends PureComponent> { - render() { - const { children, ...props } = this.props; - return {children}; - } -} - -export default SVGBase; diff --git a/src/components/Gauge/components/UnitOfMeasurement/UnitOfMeasurement.tsx b/src/components/Gauge/components/UnitOfMeasurement/UnitOfMeasurement.tsx deleted file mode 100644 index d26976fa..00000000 --- a/src/components/Gauge/components/UnitOfMeasurement/UnitOfMeasurement.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { PureComponent } from "react"; - -class UnitOfMeasurement extends PureComponent { - render() { - const { value, disabled, center, offsetText,uom ,...rest }:any = this.props; - - return ( - - {value+" "+uom} - - ); - } -} - -export default UnitOfMeasurement; diff --git a/src/components/Gauge/components/index.ts b/src/components/Gauge/components/index.ts deleted file mode 100644 index edeb7711..00000000 --- a/src/components/Gauge/components/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { default as SVGBase } from "./SVGBase/SVGBase"; -export { default as Pointer } from "./Pointer/Pointer"; -export { - default as InvertedTriangle -} from "./InvertedTriangle/InvertedTriangle"; - -export { - default as UnitOfMeasurement -} from "./UnitOfMeasurement/UnitOfMeasurement"; - -export { default as GaugeArc } from "./GaugeArc/GaugeArc"; -export { default as Label } from "./Label/Label"; -export { default as Gradient } from "./Gradient/Gradient"; diff --git a/src/components/Gauge/hooks/useGradient.tsx b/src/components/Gauge/hooks/useGradient.tsx deleted file mode 100644 index 3f08e2cd..00000000 --- a/src/components/Gauge/hooks/useGradient.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import { Gradient } from "../components"; - -const useGradient = (startColour:string, stopColour:string, id:string) => { - return { - color: `url(#${id})`, - // node: disabled => ( - // - // ) - }; -}; - -export default useGradient; diff --git a/src/components/GaugeReference.tsx b/src/components/GaugeReference.tsx deleted file mode 100644 index ca26adbd..00000000 --- a/src/components/GaugeReference.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import React, { PureComponent } from "react"; - -export default class GaugeReference extends PureComponent { - render() { - return ( - - - - - - - - - - - - - - - 50 - - - 60 - - - 80 - - - 100 - - - 120 - - - 140 - - - 150 - - - - - - - - - - - - - - - - - - - - ); - } -} diff --git a/src/components/LatestDataGauge.tsx b/src/components/LatestDataGauge.tsx deleted file mode 100644 index f9978b83..00000000 --- a/src/components/LatestDataGauge.tsx +++ /dev/null @@ -1,799 +0,0 @@ - -// GaugeWidget.tsx -import React, { useEffect, useRef, useMemo, useState } from "react"; -import * as d3 from "d3"; - -import ReactDOM from "react-dom"; - -import Gauge from "../components/Gauge/Gauge"; -import useGradient from "../components/Gauge/hooks/useGradient"; -import { CSSProperties } from "react"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { validateRequiredProps } from "../helpers/validate"; - -/** - * Helper: Normalize SxProps to plain object (like in your other widgets) - */ -const normalizeSx = ( - sx: Record | undefined -): Record => { - if (!sx) return {}; - if (Array.isArray(sx)) return Object.assign({}, ...sx); - if (typeof sx === "function") return sx({}) as Record; - return sx as Record; -}; -const defaultFontFamily = "Roboto, sans-serif"; - -interface GaugeArcStyle { - trackColor?: string; - progressColor?: string; - progressStroke?: string; - fontSize?: string | number; - fontFamily?: string; -} - -const defaultArcSx: GaugeArcStyle = { - trackColor: "#e6e6e6", // light background arc - progressColor: "#4caf50", // the β€œfilled” arc part - progressStroke: "none", - fontSize: "20px", - fontFamily: defaultFontFamily, -}; -const defaultSubtitleSx: CSSProperties = { - fontSize: "12px", - color: "#666", - fontFamily: defaultFontFamily, -}; - - -/* ---------------------- Types ---------------------- */ - -export interface Zone { - from: number; // inclusive - to: number; // exclusive - color: string; -} -type WidgetState = { - value?: any; - loading?: boolean; - error?: string | null; // βœ… matches your React state -}; - -export interface GaugeStyleSet { - container?: CSSProperties; - label?: CSSProperties; - value?: CSSProperties; - unit?: CSSProperties; -subtitle?: CSSProperties; - arc?: GaugeArcStyle; - fontFamily?: string; // optional global font family for all 3 -} - - -type StylesInput = - | GaugeStyleSet - | ((state: WidgetState) => GaugeStyleSet); - - - -export interface GaugeMetrics { - maxRadius: number; - valueAngleDeg: number; - valueAngleRad: number; - startAngleDeg: number; - endAngleDeg: number; - innerRadius: number; - outerRadius: number; - cx: number; - cy: number; -} - -export interface GaugeWidgetProps { - client: any; - nodeId: string; - variable: string; - min?: number; // default 0 - max?: number; // default 100 - startAngleDeg?: number; // degrees, default -90 (left) for semi-circle - endAngleDeg?: number; // degrees, default 90 (right) for semi-circle - thickness?: number; // thickness of the arc (absolute px) β€” default: 0.2 * radius - zones?: Zone[]; // colored zones, optional (defaults provided) - showNeedle?: boolean; // draw a needle for the value - needleColor?: string; - needleWidth?: number; - title?: string; - subtitle?: string; -styles?: StylesInput; - disabled?: boolean; //for pointer label - tickCount?: number; - unit?: string; - uomOffset?: number; - labelOffset?: number; - // callback to receive computed values (optional) - onMetrics?: (metrics: GaugeMetrics) => void; - // function that returns the inner text (defaults to "value / max") - valueText?: (opts: { - value?: number; - valueMin: number; - valueMax: number; - }) => string; - onStyleChange?:(value:number) =>{}; - displayText?: DisplayTextFormatter; -} - -type UnitPosition = "left" | "right" | "top" | "bottom"; -type UnitStyle = "normal" | "subscript" | "superscript"; - - -interface DisplayTextResult { - text: string; - unitText?: string; - position?: UnitPosition; - unitStyle?: UnitStyle; -} - -type DisplayTextFormatter = ( - value: number, - unit?: string -) => DisplayTextResult; - - -/* ---------------------- Defaults ---------------------- */ - -const defaultZones: Zone[] = [ - { from: 0, to: 40, color: "#4caf50" }, // green - { from: 40, to: 60, color: "#ffeb3b" }, // yellow - { from: 60, to: 100, color: "#f44336" }, // red -]; - -// --- Default styles --- -interface StyleSet { - - label?: CSSProperties; - value?: CSSProperties; - unit?: CSSProperties; - fontFamily?: string; // optional global font family for all 3 -} - -const defaultContainerSx: any = { - width: 400, - height: 250, - padding: 2, - margin: 0, - display: "flex", - flexDirection: "column", - justifyContent: "flex-start", - alignItems: "center", - borderRadius: 10, - boxSizing: "border-box", - background: "rgb(248, 249, 250)", - border: "1px solid rgba(211, 216, 220, 1)", -//'linear-gradient(to right, rgb(47, 99, 255), rgb(20, 110, 180))' - fontFamily: defaultFontFamily, - color:"#000000", - overflowWrap: "break-word", - label: { fontWeight: 500, color: "#000000", fontFamily: defaultFontFamily }, - value: { fontWeight: 700, color: "#000000", fontFamily: defaultFontFamily }, - unit: { fontWeight: 400, color: "#000000", fontFamily: defaultFontFamily }, - - -}; - -// --- Circuit Breaker Config --- -const MAX_FAILURES = 3; - -/* ---------------------- Component ---------------------- */ - -export const LatestDataGauge: React.FC = ({ - client, - nodeId, - variable, - title = "Latest Data", - min = 0, - max = 100, - startAngleDeg = -135, // semi-circle: -90 .. 90 - endAngleDeg = 135, - thickness, // optional - zones = defaultZones, - showNeedle = false, - needleColor = "#111", - needleWidth = 3, - subtitle, - styles = {}, - disabled = false, - tickCount = 11, - unit = "Units", - uomOffset = -15, - labelOffset = -7, - onMetrics, - valueText = ({ value: v, valueMin, valueMax }) => - v === undefined ? `-- / ${valueMax}` : `${v} / ${valueMax}`, - onStyleChange, - displayText, -}) => { - - validateRequiredProps( - "LatestDataGauge", - { client, nodeId, variable }, - ["client", "nodeId", "variable"] - ); - - const streamId="019d3dce-2043-7dbe-86fe-69387b378107" - const streamUrl="wss://ZxBpErVPCj.acs-r1.ap-in-1.anedya.io/v1/streams/connect" - - useEffect(() => { - if (!client || !nodeId || !streamId || !streamUrl) return; - mountedRef.current = true; - - const anedya = (client as any)._anedya as Anedya; - - const node = anedya.NewNode(client, nodeId); - console.log(node,"node") - const stream = node.getStream(streamId, streamUrl); - - - stream.onData((data: any) => { - if (!mountedRef.current) return; - console.log("Stream Data:", data); - }); - - stream.onError((err: any) => { - if (!mountedRef.current) return; - console.error("Stream Error:", err); - }); - - stream - .connect() - .then(() => { - if (mountedRef.current) console.log("Stream connected"); - }) - .catch((err: any) => { - console.error("Stream connect failed:", err); - }); - - return () => { - mountedRef.current = false; - stream.disconnect(); - console.log("Stream disconnected"); - }; - }, [client, nodeId, streamId, streamUrl]); - - - - const [value,setValue] = useState(null) - const [node, setNode] = useState(null); // <-- store node in state - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - // Build a state object to pass into the callback styles -const widgetState = { value, loading, error }; - - -// Resolve function or static style object -const [dynamicStyles, setDynamicStyles] = useState>({}); - -const baseResolvedStyles = - typeof styles === "function" ? styles(widgetState) : styles || {}; - -const resolvedStyles = { - container: { ...baseResolvedStyles.container, ...dynamicStyles?.container }, - label: { ...baseResolvedStyles.label, ...dynamicStyles?.label }, - value: { ...baseResolvedStyles.value, ...dynamicStyles?.value }, - unit: { ...baseResolvedStyles.unit, ...dynamicStyles?.unit }, - fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily, - subtitle: { ...defaultSubtitleSx, ...baseResolvedStyles.subtitle, ...dynamicStyles.subtitle }, - arc: { ...defaultArcSx, ...baseResolvedStyles.arc, ...dynamicStyles.arc }, - -}; - // --- Preventing stale closures / infinite renders --- - - const isFetchingRef = useRef(false); - const failureCountRef = useRef(0); - const mountedRef = useRef(false); - const svgRef = useRef(null); - - // normalize style objects - const containerSx = normalizeSx(resolvedStyles.container); - const titleSx = normalizeSx(resolvedStyles.label); - const valueTextSx = normalizeSx(resolvedStyles.value); - const subtitleSx = normalizeSx(resolvedStyles.subtitle); - const unitSx = normalizeSx(resolvedStyles.unit); - const arcSx = normalizeSx(resolvedStyles.arc); - - - // --- Container dimensions with TypeScript-safe default --- - const containerDefaults: any = defaultContainerSx!; - const width = containerSx.width ?? containerDefaults.width; - const height = containerSx.height ?? containerDefaults.height; - - // convert degrees -> radians helper - const deg2rad = (d: number) => (d * Math.PI) / 180; - - // clamp value into min..max safely - const clamp = (v?: number) => - v === undefined ? undefined : Math.max(min, Math.min(max, v)); - - // derived, memoized (fast) - const metrics = useMemo(() => { - const padding = 8; // keep inside svg - const cx = width / 2; - const cy = height / 2; - // Available radius limited by width/height and padding - const maxRadius = Math.min(width / 2, height / 2) - padding; - // default thickness if not provided: 20% of radius - const outerRadius = maxRadius; - const innerRadius = Math.max( - 6, - outerRadius - (thickness ?? Math.round(outerRadius * 0.2)) - ); - // compute value angle - const startRad = deg2rad(startAngleDeg); - const endRad = deg2rad(endAngleDeg); - // clamped value fraction - const effectiveValue = value === undefined ? undefined : clamp(value); - const frac = - effectiveValue === undefined ? 0 : (effectiveValue - min) / (max - min); - const valueAngleRad = startRad + frac * (endRad - startRad); - const valueAngleDeg = (valueAngleRad * 180) / Math.PI; - return { - maxRadius, - valueAngleDeg, - valueAngleRad, - startAngleDeg, - endAngleDeg, - innerRadius, - outerRadius, - cx, - cy, - } as GaugeMetrics; - }, [value, min, max, startAngleDeg, endAngleDeg, width, height, thickness]); - - useEffect(() => { - if (client && nodeId) { - const anedya = (client as any)._anedya as Anedya; // retrieve wrapped instance - const createdNode = anedya.NewNode(client, nodeId); - setNode(createdNode); - } -}, [client, nodeId]); - - -// --- Fetch data once safely --- - useEffect(() => { - - - mountedRef.current = true; - if (!node) return; - const fetchData= async()=> { - - if ( isFetchingRef.current|| failureCountRef.current >= MAX_FAILURES){ - - //rate limiter ----> in client - console.log("!node:",node) - console.log("isFetchingRef.current:",isFetchingRef.current) - console.log("failureCountRef.current:",failureCountRef.current) - return - }; // don't try if node not ready or if an api call is being currently made already - - isFetchingRef.current = true; - try { - setLoading(true); - setError(null); - const res = await node.getLatestData(variable); - - if (!mountedRef.current) return; // <-- SAFE, stops state update if unmounted - - if (res.isSuccess && res.isDataAvailable) { - - setValue(res.data?.value); - setError(""); - // setValue(null); - } else { - setValue(null); - console.error("error fetching data:", res.error); - setError(res.error.errorMessage); - } - failureCountRef.current = 0; // reset on success - } catch (err: any) { - if (!mountedRef.current) return; - console.error("Error fetching latest data:", err); - setValue(null); - setError(err?.message ?? "Failed to fetch data"); - failureCountRef.current += 1; - - } finally { - if (!mountedRef.current) return; - setLoading(false); - isFetchingRef.current = false; - } - } - fetchData(); - - return () => { - mountedRef.current = false; - }; - - }, [node, variable]); - - // Whenever value changes, allow user to modify styles dynamically - useEffect(() => { - if (typeof onStyleChange === "function") { - const updated = onStyleChange(value); - if (updated && typeof updated === "object") { - setDynamicStyles(updated); - } - } - }, [value]); -const formatted: DisplayTextResult = displayText - ? displayText(Number(value), unit) - : { - text: String(value ?? ""), - unitText: unit, - position: "right", - unitStyle: "normal", - }; - - - - - - // call metrics callback if provided - useEffect(() => { - if (onMetrics) onMetrics(metrics); - }, [metrics, onMetrics]); - - // D3 draw/cleanup - useEffect(() => { - const svg = svgRef.current; - if (!svg) return; - - // clear previous - d3.select(svg).selectAll("*").remove(); - - const svgSel = d3.select(svg); - - const { - cx, - cy, - outerRadius, - innerRadius, - valueAngleRad, - startAngleDeg: sDeg, - endAngleDeg: eDeg, - } = metrics; - - // group container for translation and layering - const g = svgSel.append("g").attr("transform", `translate(${cx}, ${cy})`); // center at 0,0 inside group - - // background track -> single full track from startAngle to endAngle (light gray) - const startRad = deg2rad(sDeg); - const endRad = deg2rad(eDeg); - const fullArc = d3 - .arc() - .innerRadius(innerRadius) - .outerRadius(outerRadius) - .startAngle(startRad) - .endAngle(endRad); - - const fullArcPathD = (fullArc as any)(undefined); - g.append("path") - .attr("d", fullArcPathD ?? "") - .attr("fill", arcSx.trackColor ?? "#e6e6e6") - .attr("stroke", "none"); - - // draw zones as arcs - zones may exceed min/max so map zone percentages to angles - // zones are in value units; convert zone from/to -> angles - const totalAngleSpanRad = deg2rad(eDeg - sDeg); - - const valueToAngleRad = (v: number) => { - const frac = (v - min) / (max - min); - return startRad + frac * totalAngleSpanRad; - }; - - // sanitize zones: sort and clamp to [min, max] - const safeZones = (zones ?? []) - .map((z) => ({ - from: Math.max(z.from, min), - to: Math.min(z.to, max), - color: z.color, - })) - .filter((z) => z.to > z.from) - .sort((a, b) => a.from - b.from); - - safeZones.forEach((z, idx) => { - const zStart = valueToAngleRad(z.from); - const zEnd = valueToAngleRad(z.to); - const arcFn = d3 - .arc() - .innerRadius(innerRadius) - .outerRadius(outerRadius) - .startAngle(zStart) - .endAngle(zEnd); - - const pathD = (arcFn as any)(undefined); - g.append("path") - .attr("d", pathD ?? "") - .attr("fill", z.color) - .attr("stroke", "none") - .attr("opacity", 1); - }); - - // Draw progress arc from startRad to valueAngleRad (if value defined) - if (value !== undefined) { - // don't draw if value outside range? we clamp earlier to min..max - const progArc = d3 - .arc() - .innerRadius(innerRadius) - .outerRadius(outerRadius) - .startAngle(startRad) - .endAngle(valueAngleRad); - - const progArcPathD = (progArc as any)(undefined); - g.append("path") - .attr("d", progArcPathD ?? "") - .attr("fill", arcSx.progressColor ?? "rgba(255,255,255,0.15)") - .attr("stroke", arcSx.progressStroke ?? "#00000000"); - } - - // optional needle - pointy line from center to outer radius at valueAngleRad - if (showNeedle && value !== undefined) { - const needleLen = - (innerRadius + outerRadius) / 2 + (outerRadius - innerRadius) * 0.15; - const needleG = g.append("g").attr("class", "needle"); - - // create triangular needle or line - const needleLine = d3.line(); - const nx = Math.cos(valueAngleRad - Math.PI / 2) * needleLen; - const ny = Math.sin(valueAngleRad - Math.PI / 2) * needleLen; - // Slight rotation because group center at 0,0 and d3 arc angles use 0 at 12 o'clock - // We'll produce a simple line - needleG - .append("line") - .attr("x1", 0) - .attr("y1", 0) - .attr("x2", nx) - .attr("y2", ny) - .attr("stroke", needleColor) - .attr("stroke-width", needleWidth) - .attr("stroke-linecap", "round"); - - // small center cap - needleG - .append("circle") - .attr("cx", 0) - .attr("cy", 0) - .attr("r", Math.max(3, Math.min(6, (outerRadius - innerRadius) * 0.25))) - .attr("fill", needleColor); - } - - // center value text - const valueString = valueText({ value, valueMin: min, valueMax: max }); - - const valueGroup = g.append("g").attr("class", "value-group"); - - valueGroup - .append("text") - .attr("class", "gauge-value-text") - .attr("text-anchor", "middle") - .attr("y", -((innerRadius + outerRadius) / 2) * 0.05) // slightly upward - .style( - "font-size", - (arcSx.fontSize ?? `${Math.round(innerRadius * 0.45)}px`) as string - ) - .style("font-family", arcSx.fontFamily ?? "Roboto, Arial, sans-serif") - .style("fill", (valueTextSx.color as any) ?? "#111") - .text(valueString); - - // optional subtitle below - if (subtitle) { - valueGroup - .append("text") - .attr("class", "gauge-subtitle-text") - .attr("text-anchor", "middle") - .attr("y", (outerRadius - innerRadius) * 0.6 + 14) - .style("font-size", (subtitleSx.fontSize ?? "12px") as string) - .style("fill", subtitleSx.color ?? "#666") - .text(subtitle); - } - - // cleanup on unmount - return () => { - d3.select(svg).selectAll("*").remove(); - }; - }, [ - metrics, - zones, - value, - min, - max, - showNeedle, - needleColor, - needleWidth, - valueText, - resolvedStyles, // keep redraw when style shape changes - ]); - - /** Red gradient props for arcSegments */ - const redFade = useGradient( - "rgba(255,0,0,0)", - "rgba(255,0,0,1)", - "redFade-randomkey" - ); - - /** Renders coloured arcs to demarcate target ranges. */ - const arcSegments = [ - // {min: 0, max:1, color: "#148382"} - { min: 0, max: 0.5, color: "rgb(181,230,29)" }, - { min: 0.5, max: 1, color: "orange" }, - { - min: 0.75, - max: 1, - ...redFade, - }, - ]; - - // --- Scaled font sizes --- - const baseFont = Math.min(Number(width), Number(height)) * 0.15; - - // --- Compute font sizes dynamically if not provided by user --- - const labelFont = (resolvedStyles?.label as any)?.fontSize ?? baseFont * 0.6; - - const valueFont = (resolvedStyles?.value as any)?.fontSize ?? baseFont * 1.2; - - const unitFont = (resolvedStyles?.unit as any)?.fontSize ?? baseFont * 0.8; - - // overall container style (MUI Box) - const mergedContainer = { - ...defaultContainerSx, - ...containerSx, - width, - height, - - }; - // --- Font family handling --- - const globalFontFamily = resolvedStyles?.fontFamily ?? "Roboto"; - const labelFontFamily = defaultContainerSx.label?.fontFamily ?? globalFontFamily; - const valueFontFamily = defaultContainerSx.value?.fontFamily ?? globalFontFamily; - const unitFontFamily = defaultContainerSx.label?.fontFamily ?? globalFontFamily; - - - const mergedLabelSx: CSSProperties = { - ...defaultContainerSx.label, - fontSize: labelFont, - ...titleSx, - fontFamily: labelFontFamily, - }; - const mergedValueSx: CSSProperties = { - ...defaultContainerSx.value, - fontSize: valueFont, - // color: textColor, - ...valueTextSx, - fontFamily: valueFontFamily, - }; - const mergedUnitSx: CSSProperties = { - ...defaultContainerSx.unit, - fontSize: unitFont, - ...unitSx, - fontFamily: unitFontFamily, - }; - - - return ( - -
- {title && ( -

- {title} -

- )} - {loading ? ( -
-
-
- ) : error ? ( - -
-
-{error} -
- -
- - - ) : value ? ( - - ): !value? - - -
-
-{ "No data available"} -
- -
- - :<>} - -
- ); -}; - -export default LatestDataGauge; diff --git a/src/components/LatestDataWidget.tsx b/src/components/LatestDataWidget.tsx deleted file mode 100644 index b87cbb57..00000000 --- a/src/components/LatestDataWidget.tsx +++ /dev/null @@ -1,466 +0,0 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CSSProperties } from "react"; -import { validateRequiredProps } from "../helpers/validate"; -// --- Default color ranges --- -const defaultColorRanges = [ - { max: 40, color: "#008000" }, - { max: 100, color: "#FFA500" }, - { max: Infinity, color: "#FF2C2C" }, -]; - -type WidgetState = { - value?: number; - loading: boolean; - error?: string|null; -}; - -type UnitPosition = "left" | "right" | "top" | "bottom"; -type UnitStyle = "normal" | "subscript" | "superscript"; - -interface DisplayTextResult { - text: string; - unitText?: string; - position?: UnitPosition; - unitStyle?: UnitStyle; -} - -type DisplayTextFormatter = ( - value: number, - unit?: string -) => DisplayTextResult; - -// --- Default styles --- -interface StyleSet { - container?: CSSProperties; - label?: CSSProperties; - value?: CSSProperties; - unit?: CSSProperties; - fontFamily?: string; // optional global font family for all 3 -} - - -type StylesInput = - | StyleSet - | ((state: WidgetState) => StyleSet); - - - -const defaultFontFamily = "Roboto, sans-serif"; - -const defaultStyles: Required = { - container: { - width: 400, - height: 250, - padding: 2, - margin: 0, - display: "flex", - flexDirection: "column", - justifyContent: "flex-start", - alignItems: "center", - borderRadius: 10, - boxSizing: "border-box", - background: "rgb(248, 249, 250)", - border: "1px solid rgba(211, 216, 220, 1)", -//'linear-gradient(to right, rgb(47, 99, 255), rgb(20, 110, 180))' - fontFamily: defaultFontFamily, - color:"#000000", - gap: 2, - textAlign: "center", - }, - label: { fontWeight: 500, color: "#000000", fontFamily: defaultFontFamily }, - value: { fontWeight: 700, color: "#000000", fontFamily: defaultFontFamily }, - unit: { fontWeight: 400, color: "#000000", fontFamily: defaultFontFamily }, - fontFamily: defaultFontFamily, - -}; - -// --- Helper: get color from range --- -const getColorFromRange = (value: number, ranges = defaultColorRanges) => { - const range = ranges.find((r) => value <= r.max); - return range?.color ?? "#333"; -}; - -// --- Helper: normalize sx for TypeScript --- -const normalizeSx = ( - sx: Record | undefined -): Record => { - if (!sx) return {}; - if (Array.isArray(sx)) return Object.assign({}, ...sx); - if (typeof sx === "function") return sx({}) as Record; - return sx as Record; -}; - -// --- Circuit Breaker Config --- -const MAX_FAILURES = 3; - -// --- Rate limiter settings --- -const MIN_FETCH_INTERVAL = 10000; // 10 seconds between fetches - -// --- Props --- -interface WidgetProps { - client: any; - nodeId: string; - variable: string; - title?: string; - unit?: string; - styles?: StylesInput; - displayText?: DisplayTextFormatter; - colorRange?: typeof defaultColorRanges; - colorRangeCallback?: (value: number, defaultColor: string) => string; - onStyleChange?:(value:number) =>{} -} - -export const LatestDataWidgetComponent: React.FC = ({ - client, - nodeId, - variable, - title = "Latest Data", - unit = "", - styles = {}, - displayText, - colorRange, - colorRangeCallback, - onStyleChange -}) => { - validateRequiredProps("LatestDataWidget", { client, nodeId, variable }, [ - "client", - "nodeId", - "variable", - ]); - - - const [data, setData] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [node, setNode] = useState(null); // <-- store node in state - - // --- Preventing stale closures / infinite renders --- - - const isFetchingRef = useRef(false); - const failureCountRef = useRef(0); - const mountedRef = useRef(false); - const lastFetchRef = useRef(0); - - // Build a state object to pass into the callback styles -const widgetState = { data, loading, error }; - -// Resolve function or static style object -const [dynamicStyles, setDynamicStyles] = useState>({}); - -const baseResolvedStyles = - typeof styles === "function" ? styles(widgetState) : styles || {}; - -const resolvedStyles = { - container: { ...baseResolvedStyles.container, ...dynamicStyles?.container }, - label: { ...baseResolvedStyles.label, ...dynamicStyles?.label }, - value: { ...baseResolvedStyles.value, ...dynamicStyles?.value }, - unit: { ...baseResolvedStyles.unit, ...dynamicStyles?.unit }, - fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily, -}; -const formatted: DisplayTextResult = displayText - ? displayText(Number(data), unit) - : { - text: String(data ?? ""), - unitText: unit, - position: "right", - unitStyle: "normal", - }; - - - - - useEffect(() => { - if (client && nodeId) { - const anedya = (client as any)._anedya as Anedya; // retrieve wrapped instance - const createdNode = anedya.NewNode(client, nodeId); - setNode(createdNode); - } - }, [client, nodeId]); - - // --- Fetch data once safely --- - useEffect(() => { - mountedRef.current = true; - if (!node) return; - const fetchData = async () => { - if (isFetchingRef.current || failureCountRef.current >= MAX_FAILURES) { - //rate limiter ----> in client - console.log("!node:", node); - console.log("isFetchingRef.current:", isFetchingRef.current); - console.log("failureCountRef.current:", failureCountRef.current); - return; - } // don't try if node not ready or if an api call is being currently made already - - isFetchingRef.current = true; - try { - setLoading(true); - setError(null); - const res = await node.getLatestData(variable); - - if (!mountedRef.current) return; // <-- SAFE, stops state update if unmounted - - if (res.isSuccess && res.isDataAvailable) { - - setData(res.data?.value); - setError(""); - } else { - setData(null); - console.error("error fetching data:", res.error); - setError(res.error.errorMessage); - } - failureCountRef.current = 0; // reset on success - } catch (err: any) { - if (!mountedRef.current) return; - console.error("Error fetching latest data:", err); - setData(null); - setError(err?.message ?? "Failed to fetch data"); - failureCountRef.current += 1; - } finally { - if (!mountedRef.current) return; - setLoading(false); - isFetchingRef.current = false; - } - }; - fetchData(); - - return () => { - mountedRef.current = false; - }; - }, [node, variable]); - - - // Whenever value changes, allow user to modify styles dynamically - useEffect(() => { - if (typeof onStyleChange === "function") { - const updated = onStyleChange(data); - if (updated && typeof updated === "object") { - setDynamicStyles(updated); - } - } - }, [data]); - - // --- Normalize styles --- - const containerSx = normalizeSx(resolvedStyles?.container); - const labelSx = normalizeSx(resolvedStyles?.label); - const valueSx = normalizeSx(resolvedStyles?.value); - const unitSx = normalizeSx(resolvedStyles?.unit); - - // --- Container dimensions with TypeScript-safe default --- - const containerDefaults: any = defaultStyles.container!; - const width = containerSx.width ?? containerDefaults.width; - const height = containerSx.height ?? containerDefaults.height; - - // --- Scaled font sizes --- - const baseFont = Math.min(Number(width), Number(height)) * 0.15; - - // --- Compute font sizes dynamically if not provided by user --- - const labelFont = (resolvedStyles?.label as any)?.fontSize ?? baseFont * 0.6; - - const valueFont = (resolvedStyles?.value as any)?.fontSize ?? baseFont * 3; - - const unitFont = (resolvedStyles?.unit as any)?.fontSize ?? baseFont * 0.8; - - // --- Font family handling --- - const globalFontFamily = resolvedStyles?.fontFamily ?? "Roboto"; - const labelFontFamily = labelSx.fontFamily ?? globalFontFamily; - const valueFontFamily = valueSx.fontFamily ?? globalFontFamily; - const unitFontFamily = unitSx.fontFamily ?? globalFontFamily; - - // --- Gap scaling --- - const containerGap = (containerSx as any).gap ?? baseFont * 0.2; // scale gap if user didn't pass one - - // --- Compute dynamic text color --- - const finalRange = colorRange ?? defaultColorRanges; - let textColor = getColorFromRange(Number(data) ?? 0, finalRange); - if (colorRangeCallback) { - textColor = colorRangeCallback(Number(data) ?? 0, textColor); - } - - // --- Merge styles safely --- - const mergedContainerSx: CSSProperties = { - ...defaultStyles.container, - ...containerSx, - - gap: containerGap, - - }; - const mergedLabelSx: CSSProperties = { - ...defaultStyles.label, - fontSize: labelFont, - ...labelSx, - fontFamily: labelFontFamily, - }; - const mergedValueSx: CSSProperties = { - ...defaultStyles.value, - fontSize: valueFont, - color: textColor, - ...valueSx, - fontFamily: valueFontFamily, - }; - const mergedUnitSx: CSSProperties = { - ...defaultStyles.unit, - fontSize: unitFont, - ...unitSx, - fontFamily: unitFontFamily, - }; - - - const renderUnitText = (text: string, style: UnitStyle) => { - switch (style) { - case "superscript": - return {text}; - case "subscript": - return {text}; - default: - return {text}; - } -}; - - - return ( - -
- {title &&

{title}

} - - - {loading ? ( -
-
-
- ) : error ? ( -
-
-{error} -
- -
- ) : !data ? ( -
-
-{ "No data available"} -
- -
- ) : ( - <> -
- - {/* Unit LEFT */} - {formatted.unitText && - formatted.position === "left" && -
- - {renderUnitText(formatted.unitText, formatted.unitStyle!)} -
- } - - {/* VALUE */} -
{formatted.text}
- - {/* Unit RIGHT */} - {formatted.unitText && - formatted.position === "right" && -
- - {renderUnitText(formatted.unitText, formatted.unitStyle!)} -
- } - - {/* Unit TOP */} - {formatted.unitText && - formatted.position === "top" && -
- {renderUnitText(formatted.unitText, formatted.unitStyle!)} -
- } - - {/* Unit BOTTOM */} - {formatted.unitText && - formatted.position === "bottom" && -
- {renderUnitText(formatted.unitText, formatted.unitStyle!)} -
- } -
- - )} - -
- - - ); -}; - -export default LatestDataWidgetComponent; diff --git a/src/components/chartTheme.tsx b/src/components/chartTheme.tsx deleted file mode 100644 index 9a1619a7..00000000 --- a/src/components/chartTheme.tsx +++ /dev/null @@ -1,239 +0,0 @@ -import type { ChartDataPoint } from "./ChartWidget"; - -/* ============================================================ - * ChartElementStyles - * ------------------------------------------------------------ - * Every stylable part of the chart, each taking REAL CSS - * properties (the same ones you'd use in any inline `style` - * object) instead of invented names. This is the "just like - * inline styling" shape your boss asked for β€” no new vocabulary - * to learn: `stroke`, `fill`, `strokeWidth`, `fontSize`, `color`, - * `border`, `backgroundColor`, etc. all work exactly as they do - * anywhere else in React. - * - * All standard SVG presentation properties (fill, stroke, - * strokeWidth, fontSize, opacity, ...) are valid inside a plain - * `style` object on an SVG element in every modern browser β€” so - * these get spread directly onto the corresponding // - * elements with no translation layer. - * - * The one exception is `dot.r` (circle radius): SVG geometry - * properties like radius aren't stylable via CSS, only settable - * as an element attribute β€” so it's a plain number, not part of - * CSSProperties. - * ============================================================ */ -export interface ChartElementStyles { - /** The outer card wrapper. */ - container?: React.CSSProperties; - /** The chart title text. */ - title?: React.CSSProperties; - /** The line stroke itself. Use `stroke` and `strokeWidth`. */ - line?: React.CSSProperties; - /** The filled area under the line. Use `fill` for the gradient's base color. */ - area?: React.CSSProperties; - /** Data point markers. Use `fill` for color; `r` for radius (plain number, not stylable via CSS). */ - dot?: React.CSSProperties & { r?: number }; - /** The x-axis baseline. Use `stroke`. */ - axis?: React.CSSProperties; - /** Axis tick labels. Use `fill` for color, `fontSize` for size. */ - tick?: React.CSSProperties; -} - -const ELEMENT_KEYS = [ - "container", - "title", - "line", - "area", - "dot", - "axis", - "tick", -] as const; - -/* ============================================================ - * Breakpoints & themes - * ------------------------------------------------------------ - * Container-width breakpoints (measured via ResizeObserver on - * the widget's own box β€” container-query semantics, not - * viewport/media-query semantics), matching Tailwind's default - * thresholds so the mental model transfers directly. - * ============================================================ */ -export type Breakpoint = "sm" | "md" | "lg" | "xl"; - -export const BREAKPOINTS: Record = { - sm: 640, - md: 768, - lg: 1024, - xl: 1280, -}; - -export type ThemeName = "light" | "dark"; -export const DEFAULT_THEME: ThemeName = "light"; - -/* ============================================================ - * ChartStyles β€” the full shape of the `styles` prop - * ------------------------------------------------------------ - * ONE prop carries everything: unconditional styling (the flat - * keys), per-theme overrides (`light`/`dark`), and per-breakpoint - * overrides (`sm`/`md`/`lg`/`xl`) β€” all optional, all composable. - * There's no separate "responsiveStyles" prop; responsiveness is - * just additional keys on this same object. - * - * styles={{ - * // flat keys: apply unconditionally, at every theme/size - * line: { stroke: "#7c3aed" }, - * - * // theme-specific: only applies when that theme is active - * dark: { container: { backgroundColor: "#111827" } }, - * - * // breakpoint-specific: only applies once the widget's - * // measured width crosses that threshold (mobile-first β€” - * // each larger breakpoint layers on top of smaller ones) - * sm: { tick: { fontSize: 8 } }, - * lg: { tick: { fontSize: 12 } }, - * }} - * ============================================================ */ -export type ChartStyles = ChartElementStyles & - Partial> & - Partial>; - -/* ============================================================ - * Theme presets - * ------------------------------------------------------------ - * The base layer, selected via the `theme` prop. Every value is - * plain CSS, so overriding any single token from `styles` is a - * one-line change β€” no custom shape to match. - * ============================================================ */ -export const lightTheme: ChartElementStyles = { - container: { border: "1px solid #e2e8f0", backgroundColor: "#f8fafc" }, - title: { color: "#0f172a", fontSize: 16, fontWeight: 600 }, - line: { stroke: "#1e88e5", strokeWidth: 2 }, - area: { fill: "#1e88e5" }, - dot: { fill: "#1e88e5", r: 3.5 }, - axis: { stroke: "#cbd5e1" }, - tick: { fill: "#64748b", fontSize: 10 }, -}; - -export const darkTheme: ChartElementStyles = { - container: { border: "1px solid #1e293b", backgroundColor: "#0f172a" }, - title: { color: "#f1f5f9", fontSize: 16, fontWeight: 600 }, - line: { stroke: "#60a5fa", strokeWidth: 2 }, - area: { fill: "#60a5fa" }, - dot: { fill: "#60a5fa", r: 3.5 }, - axis: { stroke: "#334155" }, - tick: { fill: "#94a3b8", fontSize: 10 }, -}; - -export const themes: Record = { - light: lightTheme, - dark: darkTheme, -}; - -/* ============================================================ - * mergeElementStyles - * ------------------------------------------------------------ - * Combines any number of ChartElementStyles, left to right, - * later sets winning per-key within each part. Because every - * part is now just a plain CSSProperties object, merging is a - * simple per-part spread β€” no custom-shape bookkeeping needed. - * ============================================================ */ -export function mergeElementStyles( - ...sets: (ChartElementStyles | undefined | null)[] -): ChartElementStyles { - const result: ChartElementStyles = {}; - for (const set of sets) { - if (!set) continue; - for (const key of ELEMENT_KEYS) { - if (set[key]) { - result[key] = { ...result[key], ...set[key] } as any; - } - } - } - return result; -} - -/** - * Pulls out just the unconditional/flat part of a ChartStyles - * object β€” i.e. everything EXCEPT the theme-name and breakpoint - * keys. This is what applies regardless of active theme or size. - */ -export function extractFlatStyles(styles: ChartStyles): ChartElementStyles { - const result: ChartElementStyles = {}; - for (const key of ELEMENT_KEYS) { - if (styles[key]) (result as any)[key] = styles[key]; - } - return result; -} - -/** - * Resolves the breakpoint-specific layers of a ChartStyles object - * for the widget's current measured width. Mobile-first cascade: - * each breakpoint the container has reached applies on top of - * smaller ones, same model as Tailwind's sm:/md:/lg:/xl: prefixes. - */ -export function resolveResponsiveStyles( - styles: ChartStyles, - containerWidth: number -): ChartElementStyles { - const layers: ChartElementStyles[] = []; - (Object.keys(BREAKPOINTS) as Breakpoint[]) - .sort((a, b) => BREAKPOINTS[a] - BREAKPOINTS[b]) - .forEach((bp) => { - if (containerWidth >= BREAKPOINTS[bp] && styles[bp]) { - layers.push(styles[bp]!); - } - }); - return mergeElementStyles(...layers); -} - -/* ============================================================ - * StyleRule / resolveStyleRules - * ------------------------------------------------------------ - * Declarative "if the latest value crosses a threshold, change - * the styling" rules. Pass these straight to the widget's - * `styleRules` prop β€” no wrapping needed, the widget evaluates - * them internally against the latest data point: - * - * styleRules={[ - * { when: (d) => d.value > 80, style: { line: { stroke: "#dc2626" } } }, - * { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, - * ]} - * - * If multiple rules match, their styles are merged in array order - * (later matching rules win on overlapping keys), so rules can be - * stacked (e.g. a broad "warning" rule plus a narrower "critical" - * rule) instead of only ever applying a single match. - * ============================================================ */ -export interface StyleRule { - when: (latest: ChartDataPoint, allData: ChartDataPoint[]) => boolean; - style: ChartElementStyles; -} - -/** - * Evaluates a set of StyleRules against the latest data point and - * returns the merged style of every rule that matched. This is what - * the widget's `styleRules` prop calls directly β€” no import needed - * on the consumer's side beyond the `StyleRule` type itself. - */ -export function resolveStyleRules( - rules: StyleRule[] | undefined, - data: ChartDataPoint[] -): ChartElementStyles { - if (!rules || !rules.length) return {}; - const latest = data[data.length - 1]; - if (!latest) return {}; - - const matched = rules.filter((rule) => rule.when(latest, data)); - return mergeElementStyles(...matched.map((rule) => rule.style)); -} - -/** - * @deprecated Prefer passing rules directly to the widget's - * `styleRules` prop β€” no wrapping required. This still works and is - * kept for anyone composing rule-based logic into their own custom - * `onStyleChange` callback by hand. - */ -export function defineStyleRules( - rules: StyleRule[] -): (data: ChartDataPoint[]) => ChartElementStyles { - return (data: ChartDataPoint[]) => resolveStyleRules(rules, data); -} \ No newline at end of file diff --git a/src/components/types.ts b/src/components/types.ts deleted file mode 100644 index b313f058..00000000 --- a/src/components/types.ts +++ /dev/null @@ -1,33 +0,0 @@ - -export interface AnedyaNode { - getNodeId(): string; - - // historical timeseries - getData(accessDataReq: any): Promise; - - // latest datapoint - getLatestData(variableIdentifier: string): Promise; - - // snapshot - getSnapshot(reqConfig: any): Promise; - - // value store API - setKey(reqConfig: any): Promise; - getKey(reqConfig: any): Promise; - deleteKey(reqConfig: any): Promise; - scanKeys(reqConfig: any): Promise; - - // device status - getDeviceStatus(lastContactThreshold: number): Promise; -} - - -export interface AnedyaClient { - tokenId: string; - tokenBytes: Uint8Array; - signatureVersionBytes: Uint8Array; - signatureVersion: string; - authorizationMode: string; - baseUrl: string; - -} diff --git a/src/hooks/AnedyaFrontendClient.ts b/src/hooks/AnedyaFrontendClient.ts deleted file mode 100644 index 651cafb6..00000000 --- a/src/hooks/AnedyaFrontendClient.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { AnedyaClient } from "../components/types"; - -let globalClient: AnedyaClient | null = null; - -// --- Global rate limiter map --- -type RateLimiter = { - lastCallTime: number; - interval: number; -}; - -const nodeRateLimiters = new Map(); - - -// --- Type for InitOptions --- -interface InitOptions { - useGlobal?: boolean; - forceReinit?: boolean; - rateLimitMs?: number; // βœ… configurable rate limit interval -} - -/** - * Initialize the Anedya client and optionally store globally. - * - * @returns client - */ - -export function anedyaClientInit( - tokenId: string, - token: string, - options?: InitOptions -): AnedyaClient { - const useGlobal = options?.useGlobal ?? false; - const forceReinit = options?.forceReinit ?? false; - const rateLimitMs = options?.rateLimitMs ?? 100; // βœ… default: 10 seconds - - if (useGlobal && globalClient && !forceReinit) { - return globalClient; - } - - const anedya = new Anedya(); - const config = anedya.newConfig(tokenId, token); - const client = anedya.newClient(config); - - // --- Patch NewNode with per-node rate limiter --- - const originalNewNode: (...args: any[]) => any = anedya.newNode.bind(anedya); - - anedya.newNode = (...args: any[]): any => { - const node = originalNewNode(...args); // βœ… now properly typed - - // Extract nodeId (second argument) - const nodeId = typeof args[1] === "string" ? args[1] : `unknown-${Date.now()}`; - - const limiter = - nodeRateLimiters.get(nodeId) || { - lastCallTime: 0, - interval: rateLimitMs, // βœ… use configurable rate limit - }; - nodeRateLimiters.set(nodeId, limiter); - - if (node.getLatestData) { - const originalGetLatestData: (...params: any[]) => Promise = - node.getLatestData.bind(node); - - node.getLatestData = async (...params: any[]): Promise => { - const now = Date.now(); - const elapsed = now - limiter.lastCallTime; - - if (elapsed < limiter.interval) { - const wait = limiter.interval - elapsed; - console.warn( - `⏳ Rate limited for node ${nodeId}: waiting ${wait}ms before next call` - ); - await new Promise((r) => setTimeout(r, wait)); - } - - limiter.lastCallTime = Date.now(); - - try { - return await originalGetLatestData(...params); - } catch (err) { - console.error(`⚠️ API call failed for node ${nodeId}:`, err); - throw err; - } - }; - } - - return node; - }; - - // Attach wrapped anedya instance to client - (client as any)._anedya = anedya; - - if (useGlobal) { - globalClient = client; - } - - return client; -} - - -/** - * Retrieve the globally initialized Anedya instance and client. - */ -export function getAnedyaClient(): AnedyaClient { - if (!globalClient) { - throw new Error( - "Anedya client not initialized! Call anedyaClientInit first." - ); - } - return globalClient; -} - -/** - * Clear the global Anedya client (for logout/reset). - */ -export function resetAnedyaClient(): void { - globalClient = null; -} - - -//tick count less -- done -//rate interval less -- dpne -//guagae not taking unit -- done -//error change-- add border and svg icon -- done -//latest data widget error not cventered -- done -// default should be white background --- done -//displaytext gauage -// Total callbacks to be provided for Number widget: 1-> Styling, 2-> Display Text Formatter - done -// Callbacks for Chart: 1-> Styling, 2-> Tick Formaters for x and y, 3-> Tooltip formatter -- done - - -//0-100 red, 40-100, yellow, less than 40 is green - done -//make value text defualt bigger in latest data -- done -//text styling label not matching in chart and latest data, one is bolder and diff font family ---done -//make chart size and all others bigger to accodomate overflow of x axis -- done -//rekmove error keywrd, make opacity higher -- done -//fix gauage value init styling -//afdd display number func in guage -//make swure its all responsive and make example responsive -//x axis tick count and y axis count -// user get input for timezone and what format u want to follow -- see how it is managed in the UI-- make callbacks more optimized and user friendly \ No newline at end of file diff --git a/src/hooks/Older.ts b/src/hooks/Older.ts deleted file mode 100644 index 93fde8cd..00000000 --- a/src/hooks/Older.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { AnedyaClient } from "../components/types"; - -let globalClient: AnedyaClient | null = null; - -interface InitOptions { - useGlobal?: boolean; // default: false - forceReinit?: boolean; // default: false -} -type RateLimiter = { - lastCallTime: number; - interval: number; -}; - -const nodeRateLimiters = new Map(); - -/** - * Initialize the Anedya client and optionally store globally. - * - * @returns client - */ -export function anedyaClientInit( - tokenId: string, - token: string, - options?: InitOptions -): AnedyaClient { - const useGlobal = options?.useGlobal ?? false; - const forceReinit = options?.forceReinit ?? false; - if (useGlobal && globalClient && !forceReinit) { - return globalClient; - } // Always create fresh instances - const anedya = new Anedya(); - const config = anedya.newConfig(tokenId, token); - const client = anedya.newClient(config); - if (useGlobal) { - globalClient = client; - } - return client; -} - -// --- Global rate limiter map --- - - - -/** - * Retrieve the globally initialized Anedya instance and client. - */ -export function getAnedyaClient(): AnedyaClient { - if (!globalClient) { - throw new Error( - "Anedya client not initialized! Call anedyaClientInit first." - ); - } - return globalClient; -} - -/** - * Clear the global Anedya client (for logout/reset). - */ -export function resetAnedyaClient(): void { - globalClient = null; -} diff --git a/src/hooks/renderLatestData.tsx b/src/hooks/renderLatestData.tsx deleted file mode 100644 index 2a297bf5..00000000 --- a/src/hooks/renderLatestData.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useState, useCallback, JSX } from "react"; - -import { AnedyaClient } from "../components/types"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; - -// --- Default color ranges --- -const defaultColorRanges = [ - { max: 20, color: "red" }, - { max: 50, color: "yellow" }, - { max: Infinity, color: "green" }, -]; -import { CSSProperties } from "react"; -import LatestDataWidgetComponent from "../components/LatestDataWidget"; - -// --- Default styles --- -interface StyleSet { - container?: CSSProperties; - label?: CSSProperties; - value?: CSSProperties; - unit?: CSSProperties; -} - -type UnitPosition = "left" | "right" | "top" | "bottom"; -type UnitStyle = "normal" | "subscript" | "superscript"; - -interface DisplayTextResult { - text: string; - unitText?: string; - position?: UnitPosition; - unitStyle?: UnitStyle; -} - -type DisplayTextFormatter = ( - value: number, - unit?: string -) => DisplayTextResult; - - -interface LatestDataWidgetProps { - client: AnedyaClient; - nodeId: string; - variable: string; - title?: string; - unit?: string; - styles?: StyleSet; - colorRange?: typeof defaultColorRanges; - colorRangeCallback?: (value: number, defaultColor: string) => string; - fontFamily? : string; - displayText?: DisplayTextFormatter; - onStyleChange?:(value:number)=>{} -} - -export const LatestDataWidget: React.FC = React.memo(( - { - client, - nodeId, - variable, - title, - unit, - styles = {}, - colorRange, - colorRangeCallback, - displayText, - onStyleChange - } -) => { - return ( - <> - - - - - ); -}, -(prev, next) => JSON.stringify(prev) === JSON.stringify(next)) diff --git a/src/hooks/useSafeFetch.ts b/src/hooks/useSafeFetch.ts deleted file mode 100644 index 0cbb8f73..00000000 --- a/src/hooks/useSafeFetch.ts +++ /dev/null @@ -1,69 +0,0 @@ -// hooks/useSafeFetch.ts -import { useEffect, useRef, useState } from "react"; - -interface UseSafeFetchOptions { - fetcher: () => Promise; - deps?: any[]; - maxFailures?: number; // circuit breaker -} - -interface UseSafeFetchResult { - data: T | null; - loading: boolean; - error: string | null; - refetch: () => void; - disabled: boolean; // true if circuit breaker tripped -} - -export function useSafeFetch({ - fetcher, - deps = [], - maxFailures = 5, -}: UseSafeFetchOptions): UseSafeFetchResult { - const [data, setData] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - const isFetchingRef = useRef(false); - const failureCountRef = useRef(0); - const mountedRef = useRef(false); - const disabledRef = useRef(false); - - const fetchData = async () => { - if (isFetchingRef.current || disabledRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - - try { - const res = await fetcher(); - setData(res); - failureCountRef.current = 0; - } catch (err: any) { - setError(err?.message ?? "Fetch failed"); - failureCountRef.current += 1; - if (failureCountRef.current >= maxFailures) { - disabledRef.current = true; - } - } finally { - isFetchingRef.current = false; - setLoading(false); - } - }; - - useEffect(() => { - if (!mountedRef.current) { - mountedRef.current = true; - fetchData(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, deps); - - return { - data, - loading, - error, - refetch: fetchData, - disabled: disabledRef.current, - }; -} diff --git a/src/index.css b/src/index.css deleted file mode 100644 index cb9f1bd6..00000000 --- a/src/index.css +++ /dev/null @@ -1,43 +0,0 @@ -@import "tailwindcss"; - -.pointer-wrapper { - position: relative; -} - -.pointer-wrapper:hover::after { - content: attr(data-tooltip); - position: absolute; - left: 50%; - top: -10px; - transform: translate(-50%, -100%); - background: black; - color: white; - padding: 4px 8px; - font-size: 12px; - border-radius: 4px; - white-space: nowrap; - pointer-events: none; -} -#gauge-tooltip { - background: rgba(0, 0, 0, 0.8); - color: white; - padding: 6px 10px; - border-radius: 6px; - font-size: 13px; - transition: opacity 0.2s ease, transform 0.2s ease; - transform: translateY(-5px); - white-space: nowrap; -} - -.spinner { - border: 4px solid rgba(0, 0, 0, 0.1); - border-top-color: rgba(0, 0, 0, 0.7); - border-radius: 50%; - animation: spin 0.8s linear infinite; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 2c9253af..7fa9d43a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -export { anedyaClientInit } from "./hooks/AnedyaFrontendClient"; -export {LatestDataWidget} from "./hooks/renderLatestData"; -export {ChartWidget} from "./components/ChartWidget" -export type { ChartWidgetProps, ChartDataPoint } from "./components/ChartWidget"; -export {LatestDataGauge} from "./components/LatestDataGauge" \ No newline at end of file + + +export {CardWidget} from "./components/CardWidget" + + diff --git a/src/themes/defaultTheme.ts b/src/themes/defaultTheme.ts new file mode 100644 index 00000000..bbf30711 --- /dev/null +++ b/src/themes/defaultTheme.ts @@ -0,0 +1,33 @@ +import { CardSlot } from "../components/CardWidget"; +import { WidgetTheme } from "../types/root"; + + +export const CARD_DEFAULT_CLASSES: Record = { + container: "flex flex-col gap-1 rounded-xl border p-4", + title: "text-sm font-medium", + value: "text-4xl font-bold", + unit: "text-[0.5em] font-normal ml-1", + label: "text-xs", +}; + + +export const lightTheme: WidgetTheme = { + classNames: { + container: "bg-white border-slate-200", + title: "text-slate-500", + value: "text-slate-900", + label: "text-slate-400", + }, +}; + +export const darkTheme: WidgetTheme = { + classNames: { + container: "bg-slate-900 border-slate-800", + title: "text-slate-400", + value: "text-white", + label: "text-slate-500", + }, +}; +export const themes = { light: lightTheme, dark: darkTheme } as const; +export type ThemeName = keyof typeof themes; +export const DEFAULT_THEME: ThemeName = "light"; \ No newline at end of file diff --git a/src/themes/theme.ts b/src/themes/theme.ts deleted file mode 100644 index 0cb3c019..00000000 --- a/src/themes/theme.ts +++ /dev/null @@ -1,31 +0,0 @@ -// theme.ts -export const widgetTheme = { - colors: { - primary: "#4f46e5", - secondary: "#06b6d4", - success: "#22c55e", - danger: "#ef4444", - warning: "#f59e0b", - - // Gradients - gradients: { - blue: ["#3b82f6", "#93c5fd"], - purple: ["#a855f7", "#e9d5ff"], - orange: ["#f97316", "#fed7aa"], - }, - - // Text Colors - textPrimary: "#ffffff", - textSecondary: "#d1d5db", - }, - - font: { - family: "Roboto, Arial, sans-serif", - size: { - small: 12, - medium: 16, - large: 20, - xlarge: 32, - }, - }, -}; diff --git a/src/types/card.ts b/src/types/card.ts new file mode 100644 index 00000000..956bf7f6 --- /dev/null +++ b/src/types/card.ts @@ -0,0 +1,7 @@ +export type CardSlot = + | "container" + | "title" + | "value" + | "unit" + | "label"; + export type BuiltInTheme = "light" | "dark"; \ No newline at end of file diff --git a/src/types/root.ts b/src/types/root.ts index 078e1ab5..22e111dd 100644 --- a/src/types/root.ts +++ b/src/types/root.ts @@ -1,11 +1,25 @@ -import { ComponentClass, FunctionComponent } from 'react'; - -// third-party - - -// ==============================|| TYPES - ROOT ||============================== // - -export type KeyedObject = { - [key: string]: string | number | KeyedObject | any; -}; +/** + * Generic per-slot class overrides. Every widget defines its own slot + * names (Card: container/title/value/unit/label, Chart: container/line/ + * axis/...) but they all share this same shape. + */ +export type SlotClassNames = + Partial>; +/** + * A widget theme is simply a reusable collection of Tailwind (or plain + * CSS) classes for a widget's slots. + * + * Themes are merged in three layers: + * + * built-in theme + * ↓ + * user theme + * ↓ + * widget classNames prop + * + * Later layers win via `twMerge`. + */ +export interface WidgetTheme { + classNames: SlotClassNames; +} \ No newline at end of file diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index 3ae766b8..390f6bfa 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -8,6 +8,9 @@ "name": "my-app", "version": "0.0.0", "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/material": "^9.2.0", "react": "^19.2.4", "react-dom": "^19.2.4" }, @@ -30,7 +33,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", @@ -86,7 +88,6 @@ "version": "7.29.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", @@ -120,7 +121,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -130,7 +130,6 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", @@ -162,7 +161,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -172,7 +170,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -206,7 +203,6 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -218,11 +214,19 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", @@ -237,7 +241,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", @@ -256,7 +259,6 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -303,6 +305,158 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -516,7 +670,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -538,7 +691,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -548,20 +700,225 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mui/core-downloads-tracker": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-9.2.0.tgz", + "integrity": "sha512-+XMav+ZaXkZKUFUgzjrfMEedfyJKxxviAske2q8N8CWDMeqZdDU2lWMkiUPiB388hGaDqhwvOAwkrsc/pUyp8g==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.2.0.tgz", + "integrity": "sha512-+YTRSgGKGrrRo2XJZXs7JRA6qHoHWvNtxyqxnrRJTBmIuLOUpxxh7m4G9lF4tWberxGFY+EqkkRPgJCl+fSMJg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/core-downloads-tracker": "^9.2.0", + "@mui/system": "^9.2.0", + "@mui/types": "^9.1.1", + "@mui/utils": "^9.2.0", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.2.3", + "prop-types": "^15.8.1", + "react-is": "^19.2.6", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^9.2.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-9.2.0.tgz", + "integrity": "sha512-w9wpyDxGPGnAACPB2hKhCDmILJIAvQxrfjUbIAEa0AznX1rOjaz5N+yB1uuw8ixnJcpEh/tPbD9oEe19wcWPHw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/utils": "^9.2.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-9.1.1.tgz", + "integrity": "sha512-neaYKdJfvEG54q8efHLJR7swpHG/gfSv9xGqW5iTSMsubD7yPCPFrhVBt284j1DOF3uZaaDJSHQL7gz6jGF21Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.2.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-9.2.0.tgz", + "integrity": "sha512-YvUJwKoGVtbnOm2PyPi5TvX2d1rOA6sqSpEWVs4WmXNIaFTuYmNUaVdU2o1NKUEe31URnD3E8ZVUMcsLQXwcYg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/private-theming": "^9.2.0", + "@mui/styled-engine": "^9.1.1", + "@mui/types": "^9.1.1", + "@mui/utils": "^9.2.0", + "clsx": "^2.1.1", + "csstype": "^3.2.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.1.1.tgz", + "integrity": "sha512-Zjt7u8wNvDg40rPTGoL+TnfkpuSKjwubsNSFRH1KAVZLcaV4I3AFNHIFbvH7p4F3alEibSbdd90xAgn5Rnfndg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.2.0.tgz", + "integrity": "sha512-OsUH5zhlSOM4xmLl53+agug1M1UyWb4zxFxWQCqwKTKUeQPvTENtg3JhrroBD2qpCLKsX5W/DYGERJ4mBUbc8g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/types": "^9.1.1", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.2.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", @@ -591,6 +948,16 @@ "url": "https://github.com/sponsors/Boshen" } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rolldown/binding-android-arm64": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", @@ -909,11 +1276,22 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -929,6 +1307,15 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@vitejs/plugin-react": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", @@ -1018,6 +1405,21 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-react-compiler": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", @@ -1097,7 +1499,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -1141,6 +1542,15 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1175,6 +1585,31 @@ "dev": true, "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -1194,14 +1629,12 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, "license": "MIT" }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1232,6 +1665,16 @@ "node": ">=8" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.329", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz", @@ -1239,6 +1682,24 @@ "dev": true, "license": "ISC" }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1253,7 +1714,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -1498,6 +1958,12 @@ "node": ">=16.0.0" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1551,6 +2017,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -1597,6 +2072,18 @@ "node": ">=8" } }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -1614,6 +2101,21 @@ "hermes-estree": "0.25.1" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1628,7 +2130,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -1651,6 +2152,27 @@ "node": ">=0.8.19" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1685,7 +2207,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -1705,7 +2226,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -1721,6 +2241,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2033,6 +2559,12 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2056,6 +2588,18 @@ "dev": true, "license": "MIT" }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2083,7 +2627,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -2119,6 +2662,15 @@ "dev": true, "license": "MIT" }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2173,7 +2725,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -2182,6 +2733,24 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2202,11 +2771,25 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -2261,6 +2844,23 @@ "node": ">= 0.8.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2292,11 +2892,53 @@ "react": "^19.2.4" } }, + "node_modules/react-is": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", + "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "license": "MIT" + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -2382,6 +3024,15 @@ "node": ">=8" } }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2405,6 +3056,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2418,6 +3075,18 @@ "node": ">=8" } }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -2608,6 +3277,24 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/test/my-app/package.json b/test/my-app/package.json index 1df23585..a6a8f091 100644 --- a/test/my-app/package.json +++ b/test/my-app/package.json @@ -10,6 +10,9 @@ "preview": "vite preview" }, "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/material": "^9.2.0", "react": "^19.2.4", "react-dom": "^19.2.4" }, diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index eac61765..e28aed1f 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -1,79 +1,86 @@ + import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { - LatestDataWidget, - // anedyaClientInit, - ChartWidget, - LatestDataGauge, -} from "../../../src/index"; +import { CardWidget } from "../../../src"; + -function App() { const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; - const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); const client = anedya.newClient(config); +const node = anedya.newNode(client, nodeId); - // const client = anedyaClientInit(tokenId, token); -//default min and max -//client ki implementatrion bahar lelo +/** + * A reusable theme that can be shared across multiple widgets. + * Only specify the classes you actually want to change. + */ +const emeraldTheme = { + classNames: { + container: "bg-emerald-50 border-emerald-200", + title: "text-emerald-700", + value: "text-emerald-900", + label: "text-emerald-500", + }, +}; - //019f5f58-2a58-733e-81cc-fbec233a9856 - //wss://ZxBpErVPCj.acs-r1.ap-in-1.anedya.io/v1/streams/connect +export default function App() { + return ( +
+ {/* Default appearance */} + - const currentTime = Date.now(); // ms timestamp -const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp + {/* Reusable theme */} + - return ( -
-

Test Widget SDK

-
-
- alignItems: "center", - - }} - > - -
- - -
+ {/* Plain CSS */} +
); -} - -export default App; - - -//create react app -//link public-widget-sdk -//npm run dev -//send this file tp yash to copy paste \ No newline at end of file +} \ No newline at end of file diff --git a/test/my-app/src/globals.css b/test/my-app/src/globals.css new file mode 100644 index 00000000..43ce5c51 --- /dev/null +++ b/test/my-app/src/globals.css @@ -0,0 +1,54 @@ +@import "tailwindcss"; + +:root { + --background: 0 0% 100%; + --foreground: 222 47% 11%; + --card: 0 0% 100%; + --card-foreground: 222 47% 11%; + --border: 214 32% 91%; + --muted-foreground: 215 16% 47%; + --primary: 221 83% 53%; + --secondary: 262 83% 58%; + --destructive: 0 84% 60%; + --radius: 0.75rem; +} + +.dark { + --background: 222 47% 11%; + --foreground: 210 40% 98%; + --card: 222 47% 15%; + --card-foreground: 210 40% 98%; + --border: 217 33% 24%; + --muted-foreground: 215 20% 65%; + --primary: 217 91% 60%; + --secondary: 262 83% 68%; + --destructive: 0 63% 60%; + --radius: 0.75rem; +} + +.my-card { + background: #1e1b4b; + border: 1px solid #4338ca; + border-radius: 10px; + padding: 18px; +} + +.my-card-title { + color: #a5b4fc; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.my-card-value { + color: #eef2ff; + font-size: 42px; + font-weight: 800; + font-variant-numeric: tabular-nums; +} + +.my-card-label { + color: #818cf8; + font-size: 11px; +} \ No newline at end of file From 24191c785bee749200313d8e670be20e750d1d24 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 17 Jul 2026 17:40:03 +0530 Subject: [PATCH 18/66] removed style prop --- src/common.ts | 1 - src/components/CardWidget.tsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common.ts b/src/common.ts index 710790c8..d24c06dd 100644 --- a/src/common.ts +++ b/src/common.ts @@ -36,7 +36,6 @@ theme?: WidgetTheme | BuiltInTheme; /** Applied to the widget's outermost element, on top of everything else. */ className?: string; - style?: React.CSSProperties; // Sizing β€” stay as direct props (shorthand for the container's // width/height), matching the existing ChartWidget convention. diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 10f58ffc..16b782c5 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -44,7 +44,7 @@ export function CardWidget({ theme, classNames = {}, className, - style, + width, height, minWidth = DEFAULT_MIN_WIDTH, @@ -150,7 +150,7 @@ const resolveSlot = (slot: CardSlot) => maxWidth, height, boxSizing: "border-box", - ...style, + }} > Date: Fri, 17 Jul 2026 18:18:27 +0530 Subject: [PATCH 19/66] commit --- test/my-app/src/App.jsx | 123 ++++++++++++++++++++-------------------- 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 992ed0a6..5c2be6b4 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -1,11 +1,10 @@ - import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; - const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; +const token = + "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; const anedya = new Anedya(); @@ -28,15 +27,19 @@ const emeraldTheme = { export default function App() { return ( -
-

Test Widget SDK

+

+ Test Widget SDK +

- +
{/*
+ - {/* Per-instance overrides */} - + {/* Per-instance overrides */} + - {/* Plain CSS */} - + {/* Plain CSS */} + +
); } -export default App; - - +{ + /* //create react app //link public-widget-sdk //npm run dev -//send this file tp yash to copy paste \ No newline at end of file +//send this file tp yash to copy paste */ +} From 57fe1379f0f68c8d70d8317c7ac071aed4c45cdb Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Wed, 22 Jul 2026 16:26:29 +0530 Subject: [PATCH 20/66] updated callbacks to include all optional props and added responsiveness --- README.md | 336 ++++++++++++++++++++++------------ dist/style.css | 2 + package-lock.json | 140 +++++++------- package.json | 2 +- src/common.ts | 2 - src/components/CardWidget.tsx | 211 ++++++++++++++------- src/styles/base.css | 53 ++++++ src/themes/defaultTheme.ts | 20 +- test/my-app/src/App.jsx | 157 ++++++++++++---- 9 files changed, 623 insertions(+), 300 deletions(-) create mode 100644 dist/style.css create mode 100644 src/styles/base.css diff --git a/README.md b/README.md index 609fc81f..087823bd 100644 --- a/README.md +++ b/README.md @@ -1,196 +1,290 @@ -# ChartWidget +# CardWidget -A responsive, themeable line chart widget for Anedya data, built on D3 + SVG. +A single-value display widget for Anedya data β€” shows the latest reading, a title, and a last-updated label. ## Setup -The widget doesn't create its own SDK client β€” you create it yourself and pass it in: +The widget doesn't create its own SDK client or node β€” you create both yourself and pass the node in: ```jsx import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { ChartWidget } from "your-sdk"; +import { CardWidget } from "your-sdk"; const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); const client = anedya.newClient(config); +const node = anedya.newNode(client, nodeId); - + ``` -`anedya` and `client` are both required β€” node creation is `anedya.newNode(client, nodeId)`, a method on the top-level SDK instance, not on the client. - ## Required props | Prop | Type | Description | |---|---|---| -| `anedya` | `any` | The `new Anedya()` instance | -| `client` | `any` | `anedya.newClient(config)` | -| `nodeId` | `string` | Node to fetch from | -| `variable` | `string` | Variable name to chart | -| `from` | `number` | Start timestamp (ms) | -| `to` | `number` | End timestamp (ms) | +| `node` | `any` | `anedya.newNode(client, nodeId)` | +| `variable` | `string` | Variable name to display | ## The styling model -Every stylable part of the chart is a named slot, and every value inside it is **plain CSS** β€” the same properties you'd use in any inline `style` object. Nothing invented, nothing to memorize: +Unlike `ChartWidget` (which uses inline `style` objects), `CardWidget` is **entirely class-based** β€” every visual choice is a CSS class string, not a style property. This is deliberate: Card widgets are commonly styled with Tailwind, and classes compose and override far more predictably than inline styles do once you're combining a theme, a per-instance override, and a conditional rule all on the same element. + +Every part of the card is a named **slot**: ```ts -interface ChartElementStyles { - container?: React.CSSProperties; // outer card β€” border, backgroundColor, width, etc. - title?: React.CSSProperties; - line?: React.CSSProperties; // stroke, strokeWidth - area?: React.CSSProperties; // fill β€” base color for the gradient under the line - dot?: React.CSSProperties & { r?: number }; // fill for color; r for radius (the one non-CSS exception) - axis?: React.CSSProperties; // stroke - tick?: React.CSSProperties; // fill, fontSize -} +type CardSlot = "container" | "title" | "value" | "unit" | "label"; ``` -These are spread directly onto the corresponding SVG elements (``, etc.) β€” all standard SVG presentation properties (`fill`, `stroke`, `strokeWidth`, `fontSize`, `opacity`, ...) work as real CSS in every modern browser, so there's no translation layer. +## `classNames` vs `className` β€” the distinction that matters most -**One exception:** `dot.r` (circle radius) is a plain number, not a CSS property β€” SVG geometry attributes like radius aren't stylable via CSS, only settable directly on the element. +These look similar but do genuinely different things: -## The `styles` prop β€” everything in one place +| | Shape | Targets | Purpose | +|---|---|---|---| +| `classNames` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) *and* `container` | reach inside the widget | +| `className` | plain string | only the outermost container element | the ordinary React convention every component supports | -There's a single `styles` prop. It optionally accepts three *kinds* of keys, all in the same object: -// class definition ```jsx - ``` -`styles` can also be a function of the widget's current state, if styling needs to depend on load/error status rather than just data: +Both can be used together freely β€” `className` is merged (via `twMerge`) with whatever `classNames.container` already resolved to; it doesn't replace it. -```jsx -styles={(state) => (state.error ? { container: { border: "1px solid red" } } : {})} -``` +## Theming -### Theme defaults +`theme` accepts a built-in preset name, or a full custom `WidgetTheme` object β€” just a plain object shaped like `classNames`, reusable across every widget instance that uses it: ```jsx - // or "light" (default) +const emeraldTheme: WidgetTheme = { + classNames: { + container: "bg-emerald-50 border-emerald-200", + title: "text-emerald-700", + value: "text-emerald-900", + label: "text-emerald-500", + }, +}; + + +// or + // built-in preset, or "light" (default) ``` -`lightTheme` and `darkTheme` (exported from the package) are just `ChartElementStyles` objects with sensible default colors β€” nothing special about them. Setting `theme` picks which one seeds the chart. +## Tailwind responsive utilities -### Breakpoints +You can freely use Tailwind's responsive prefixes inside `classNames`: + +```tsx + +``` -Breakpoints are measured against the **widget's own rendered width** via `ResizeObserver` β€” container-query semantics, not the browser window. This means the chart responds correctly no matter where it's embedded (a sidebar, a dashboard tile, a modal), regardless of how wide the actual browser window is. -//take definitrion from user for breakpoints -| Breakpoint | Min width | -|---|---| -| `sm` | 640px | -| `md` | 768px | -| `lg` | 1024px | -| `xl` | 1280px | +These breakpoints come entirely from your application's Tailwind configuration and respond to the browser viewport. -Resolution is mobile-first: each breakpoint the container has reached merges on top of smaller ones, same as Tailwind's `sm:`/`md:`/`lg:`/`xl:` prefixes. +They are independent of the widget's built-in container-query sizing. -## Sizing β€” the same system, not a separate one +If you supply your own `text-*` classes (responsive or otherwise), they replace the widget's default responsive typography for that slot. -`width`, `minWidth`, `maxWidth`, `height`, `minHeight`, `maxHeight` are just CSS properties living on `container`. That means sizing goes through the *exact same* flat β†’ theme β†’ breakpoint pipeline as everything else β€” which is what makes the following four cases fall out naturally, with no special-case logic: +## `onDataChange` β€” data-driven rendering +`onDataChange` is called whenever the latest fetched data changes. -```jsx -// Fully fixed β€” no breakpoint overrides anywhere, so it never changes - +It receives the raw fetched data: -// Fixed by default, but steps to a new size at a breakpoint (opt-in responsiveness) - { + if (!data) return; + + if (data.value > 80) { + return { + title: "High Humidity", + theme: "dark", + classNames: { + value: "text-red-500", + }, + }; + } + }} /> +``` -// Fluid β€” continuously follows the container, clamped between bounds - +Returning `undefined` (or nothing) clears any previous overrides and restores the widget's original props. -// Fluid, where the clamp bounds themselves step at a breakpoint - +## How props are resolved -// Nothing passed at all β€” fully responsive with built-in defaults -// (clamped between 280–1200px wide, 200–700px tall) - -``` +Rendering happens in layers. -The `width`/`height`/`minWidth`/`maxWidth`/`minHeight`/`maxHeight` **props** are shorthand for setting these same properties unconditionally on `styles.container` β€” if you also set them explicitly inside `styles`, the `styles` value wins. +1. The props you pass to `` +2. Any temporary overrides returned from `onDataChange` +3. Theme resolution (`"light"`, `"dark"`, or a custom `WidgetTheme`) +4. Per-slot class resolution -If the container ever gets smaller than the resolved `minWidth`, the chart doesn't get crushed β€” the outer wrapper scrolls horizontally (`overflowX: auto`) instead of squishing the content. +For each slot (`container`, `title`, `value`, `unit`, `label`), classes are merged in this order: -## Callbacks β€” data-driven styling +1. `CARD_DEFAULT_CLASSES` +2. Active theme classes +3. `classNames` -For simple "if a threshold is crossed, change the styling" logic, pass `styleRules` directly β€” no wrapping function needed, the widget evaluates it internally against the latest data point: -//update this -```jsx - d.value > 80, style: { line: { stroke: "#dc2626" } } }, - { when: (d) => d.value < 20, style: { line: { stroke: "#2563eb" } } }, - ]} +Later layers win whenever two Tailwind utilities conflict. Conflicts are resolved with `twMerge`. + +`className` is separate from this chainβ€”it is merged onto the outer container after the container slot has been resolved. + +> **Rule of thumb:** defaults β†’ theme β†’ `classNames` β†’ `onDataChange`. User overrides always win. + +## Formatting vs rendering + +`formatValue` and `labelText` control **what text is displayed**. + +`classNames` controls **how the widget looks**. + +`onDataChange` can override either one (along with most other widget props), allowing the widget to react to incoming data. + +For example: + +```tsx + `${v.toFixed(2)} % RH`} + labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} + onDataChange={(data) => { + if (!data) return; + + if (data.value > 80) { + return { + title: "High Humidity", + classNames: { + value: "text-red-500", + }, + }; + } + }} /> ``` -If multiple rules match, their styles merge in array order (later rules win on overlapping keys), so rules can stack β€” e.g. a broad "warning" rule plus a narrower "critical" rule. +## Sizing -For anything beyond simple threshold matching, `onStyleChange` runs whenever the fetched data changes and returns a `ChartElementStyles` object (the same flat shape as `styles`) for full custom logic: +`width`/`height`/`minWidth`/`maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole classNames/theme system, same convention as `ChartWidget`: ```jsx - { - const latest = data[data.length - 1]; - const avg = data.reduce((sum, d) => sum + d.value, 0) / data.length; - return latest?.value > avg * 1.5 ? { line: { stroke: "#dc2626" } } : {}; + +``` +## Responsive sizing + +The widget automatically scales its internal spacing and typography based on the size of the card itself using **CSS Container Queries**. + +By default the following properties scale automatically: + +- container padding +- title font size +- value font size +- unit font size +- label font size +- spacing (`gap`) + +Unlike Tailwind's `sm:`/`md:` responsive utilities (which respond to the browser viewport), container queries respond to the widget's own rendered width. + +For example, a card inside a narrow dashboard column will use smaller typography than the same card rendered full-width, even on the same screen. + +This behavior is built inβ€”you don't need to configure anything. + +### Overriding responsive sizing + +If you provide your own font-size utility for a slot, you're opting out of the default responsive sizing for that slot. + +For example: + +```tsx + ``` -If both `styleRules` and `onStyleChange` are used together, `styleRules` resolves first and `onStyleChange` applies on top β€” so custom logic can still override a rule if needed. +The value will always render at `text-6xl`. + +Likewise, if you provide responsive Tailwind classes: -## Full resolution order +```tsx +classNames={{ + value: "text-2xl md:text-5xl" +}} +``` -Low to high precedence β€” later layers win on any overlapping property: +your own breakpoint rules take precedence over the widget's default responsive sizing. -1. **Theme preset** (`lightTheme` / `darkTheme`) -2. **Sizing shorthand props** (`width`, `minWidth`, etc.) -3. **`styles`' flat keys** -4. **`styles`' active theme key** (`styles.light` or `styles.dark`) -5. **`styles`' active breakpoint keys** (mobile-first cascade) -6. **`styleRules` + `onStyleChange` result** β€” always wins, since it's live and data-driven (`styleRules` resolves first, `onStyleChange` on top) +This follows normal Tailwind behaviorβ€”your classes always win over the widget defaults. ## Other props | Prop | Type | Description | |---|---|---| -| `title` | `string` | Chart title. Default: `"Latest Data"` | -| `limit` | `number` | Max data points fetched. Default: `20` | -| `tickCount` | `number` | X-axis tick count (auto-reduced on narrow containers) | -| `xTickFormat` / `yTickFormat` | `string \| function` | Custom tick label formatting | -| `tooltipFormat` | `(point) => React.ReactNode` | Custom tooltip content β€” can return a string or rich JSX | -| `aspectRatio` | `number` | Width-to-height ratio used to derive height when no fixed/resolved height is set. Default: `1.6` | +| `title` | `string` | Card title. Default: `"Latest Value"` | +| `unit` | `string` | Unit suffix shown next to the value | +| `precision` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | + +## Build & distribution β€” why classes render unstyled without this + +Since this SDK is installed as a real package (not copied into the consumer's own repo, the way shadcn/ui works), the consumer's own Tailwind build **never scans this package's source files** by default β€” so every class string in `themes/defaultTheme.ts`/`CARD_DEFAULT_CLASSES` compiles to nothing in their app, and every widget renders with zero layout or color. This isn't a bug in the widget; it's a structural consequence of shipping Tailwind classes from an installable package. + +**The fix: ship a pre-compiled stylesheet as part of this SDK's own build**, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. + +**1. Create the input file**, `src/styles/base.css`: + +```css +@import "tailwindcss"; + +/* Explicit @source directives so Tailwind scans exactly the folders + containing our class strings, rather than relying purely on + automatic detection. Paths are relative to this file's location. */ +@source "../widgets/**/*.{ts,tsx}"; +@source "../themes/**/*.{ts,tsx}"; +@source "../common.ts"; +``` + +**2. Install the Tailwind v4 CLI** (a separate package from core `tailwindcss` as of v4): + +```bash +npm install -D @tailwindcss/cli +``` + +**3. Add a build script**, in `package.json`: + +```json +{ + "scripts": { + "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify" + } +} +``` + +Run it as part of your normal publish/build step (e.g. chain it into `prepublishOnly` or your existing `build` script) so `dist/style.css` always reflects the current source. + +**4. Consumers import it once**, anywhere in their app: + +```jsx +import "your-sdk/dist/style.css"; +``` + +That's the entire integration on their end β€” no `content` glob changes, no Tailwind config coordination, no knowledge of how this SDK is built internally required. -## Known follow-ups -- Tooltips currently use Base UI (`@base-ui/react/tooltip`); a swap to a D3-based tooltip is planned separately. -- Axis styling currently supports a single stroke color/width, not per-axis-segment overrides. -- No dot-decimation yet on very narrow/dense containers (many points can visually overlap). +- `style` (a plain inline-style object, part of the shared base props every widget accepts) isn't currently wired into the container's render β€” only `className` is. If you need it, flag it and it can be added the same way `className` already works. diff --git a/dist/style.css b/dist/style.css new file mode 100644 index 00000000..9097ed1f --- /dev/null +++ b/dist/style.css @@ -0,0 +1,2 @@ +/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-blue-500:oklch(62.3% .214 259.815);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.ml-1{margin-left:var(--spacing)}.contents{display:contents}.flex{display:flex}.inline{display:inline}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.gap-1{gap:var(--spacing)}.rounded{border-radius:.25rem}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-4{padding:calc(var(--spacing) * 4)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.5em\]{font-size:.5em}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-blue-500{color:var(--color-blue-500)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 5c554d04..21f1137c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ }, "devDependencies": { "@base-ui/react": "^1.6.0", - "@tailwindcss/cli": "^4.3.2", + "@tailwindcss/cli": "^4.3.3", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", @@ -1383,68 +1383,68 @@ ] }, "node_modules/@tailwindcss/cli": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.3.2.tgz", - "integrity": "sha512-Fzt+HrIZHDlkRYKdLMBeufaroaPvwCBG70sMLdmurdeadNMO/LxbmT8Sbb+P83ep0iAlAImettb7Y+rO+37rXw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.3.3.tgz", + "integrity": "sha512-ZvS/n1ZHOBKcVlhkt8l5NNr1EDXk1NboYO5CYDOs6NUmvT9z6bzkwsosaJftY57T/3gWNzWMJzIXLodZC8ssdw==", "dev": true, "license": "MIT", "dependencies": { "@parcel/watcher": "2.5.1", - "@tailwindcss/node": "4.3.2", - "@tailwindcss/oxide": "4.3.2", - "enhanced-resolve": "5.21.6", + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "enhanced-resolve": "^5.24.1", "mri": "^1.2.0", "picocolors": "^1.1.1", - "tailwindcss": "4.3.2" + "tailwindcss": "4.3.3" }, "bin": { "tailwindcss": "dist/index.mjs" } }, "node_modules/@tailwindcss/node": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz", - "integrity": "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "5.21.6", + "enhanced-resolve": "^5.24.1", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.3.2" + "tailwindcss": "4.3.3" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.2.tgz", - "integrity": "sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", "dev": true, "license": "MIT", "engines": { "node": ">= 20" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.2", - "@tailwindcss/oxide-darwin-arm64": "4.3.2", - "@tailwindcss/oxide-darwin-x64": "4.3.2", - "@tailwindcss/oxide-freebsd-x64": "4.3.2", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.2", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.2", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.2", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.2", - "@tailwindcss/oxide-linux-x64-musl": "4.3.2", - "@tailwindcss/oxide-wasm32-wasi": "4.3.2", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.2", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.2" + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz", - "integrity": "sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", "cpu": [ "arm64" ], @@ -1459,9 +1459,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz", - "integrity": "sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", "cpu": [ "arm64" ], @@ -1476,9 +1476,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz", - "integrity": "sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", "cpu": [ "x64" ], @@ -1493,9 +1493,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz", - "integrity": "sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", "cpu": [ "x64" ], @@ -1510,9 +1510,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz", - "integrity": "sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", "cpu": [ "arm" ], @@ -1527,9 +1527,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz", - "integrity": "sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", "cpu": [ "arm64" ], @@ -1544,9 +1544,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz", - "integrity": "sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", "cpu": [ "arm64" ], @@ -1561,9 +1561,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz", - "integrity": "sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", "cpu": [ "x64" ], @@ -1578,9 +1578,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz", - "integrity": "sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", "cpu": [ "x64" ], @@ -1595,9 +1595,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz", - "integrity": "sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -1625,9 +1625,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz", - "integrity": "sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", "cpu": [ "arm64" ], @@ -1642,9 +1642,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz", - "integrity": "sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", "cpu": [ "x64" ], @@ -2868,9 +2868,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.21.6", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", - "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3733,9 +3733,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", - "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 14d655c2..5b92d537 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ }, "devDependencies": { "@base-ui/react": "^1.6.0", - "@tailwindcss/cli": "^4.3.2", + "@tailwindcss/cli": "^4.3.3", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", diff --git a/src/common.ts b/src/common.ts index d24c06dd..44dfee98 100644 --- a/src/common.ts +++ b/src/common.ts @@ -15,8 +15,6 @@ import { WidgetTheme } from "./types/root"; */ export interface AnedyaWidgetBaseProps { node: any; - client: any; - nodeId: string; variable: string; /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ from?: number; diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 16b782c5..67a50cb0 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -1,13 +1,27 @@ import { useEffect, useMemo, useRef, useState } from "react"; -import clsx from "clsx"; import { twMerge } from "tailwind-merge"; import { AnedyaWidgetBaseProps } from "../common"; import { SlotClassNames, WidgetTheme } from "../types/root"; -import { CARD_DEFAULT_CLASSES, darkTheme, lightTheme } from "../themes/defaultTheme"; +import { + CARD_DEFAULT_CLASSES, + darkTheme, + lightTheme, +} from "../themes/defaultTheme"; export type CardSlot = "container" | "title" | "value" | "unit" | "label"; +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +export interface CardData { + value: number; + timestamp: number; +} +export type CardWidgetUpdate = Partial< + Omit< + CardWidgetProps, + "node" | "variable" | "onDataChange" + > +>; export interface CardWidgetProps extends AnedyaWidgetBaseProps { unit?: string; /** Decimal places for the displayed value. Omit to show the raw value as-is. */ @@ -18,21 +32,48 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { /** * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, anything. When a slot ends up - * with a class from here AND/OR a matched `styleRules`/ - * `onStyleChange` result, this widget's own inline theme styling for - * that slot is skipped entirely, so your class(es) have full, - * uncontested control. + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. */ classNames?: SlotClassNames; - + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * classNames: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; } const DEFAULT_WIDTH = 240; const DEFAULT_MIN_WIDTH = 180; const DEFAULT_MAX_WIDTH = 480; - export function CardWidget({ node, variable, @@ -41,8 +82,9 @@ export function CardWidget({ precision, formatValue, labelText, - theme, classNames = {}, + onDataChange, + theme, className, width, @@ -55,7 +97,11 @@ export function CardWidget({ const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - + // Holds the temporary prop overrides returned by onDataChange. + // Whenever the callback returns nothing (or the condition no longer + // matches), this resets back to {} so the widget falls back to the + // original props it was created with. + const [dynamicProps, setDynamicProps] = useState({}); const mountedRef = useRef(false); const isFetchingRef = useRef(false); @@ -99,63 +145,99 @@ export function CardWidget({ }; }, [node, variable]); -const resolvedTheme: WidgetTheme = - theme === "dark" - ? darkTheme - : theme === "light" - ? lightTheme - : theme ?? lightTheme; - - // Per-slot resolution: - // - className: static `classNames` prop + rule-driven classes, - // combined via clsx then twMerge β€” resolves real Tailwind - // conflicts between the two sources (e.g. a static text color - // class and a rule-matched one) rather than leaving both in the - // DOM with an unpredictable winner based on stylesheet order. - // - style: the theme's default inline style for that slot β€” - // skipped ENTIRELY if any class exists for that slot (from either - // source), so the class has full control. An inline style would - // otherwise silently win over a class regardless of source, since - // that's just how CSS specificity works. -const resolveSlot = (slot: CardSlot) => - twMerge( - CARD_DEFAULT_CLASSES[slot], - resolvedTheme.classNames[slot], - classNames[slot] - ); + // Resolve onDataChange whenever the fetched data changes. + // The callback returns temporary prop overrides which layer on top + // of the widget's original props. + useEffect(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + + const data = + value != null && timestamp != null ? { value, timestamp } : null; + + setDynamicProps(onDataChange(data) ?? {}); + }, [value, timestamp, onDataChange]); + const resolvedProps = { + title, + unit, + precision, + formatValue, + labelText, + width: width ?? DEFAULT_WIDTH, + height, + minWidth, + maxWidth, + className, + theme, + ...dynamicProps, + + classNames: { + ...(classNames ?? {}), + ...(dynamicProps.classNames ?? {}), + }, + }; + + const resolvedTheme: WidgetTheme = + resolvedProps.theme === "dark" + ? darkTheme + : resolvedProps.theme === "light" + ? lightTheme + : (resolvedProps.theme ?? lightTheme); + + // Per-slot resolution, lowest to highest precedence: + // 1. CARD_DEFAULT_CLASSES[slot] β€” built-in baseline + // 2. resolvedTheme.classNames[slot] β€” active theme's classes + // 3. resolvedProps.classNames + // (original classNames merged with any returned by onDataChange) + + // twMerge resolves any real Tailwind conflicts between these layers + // based on actual utility groups, not the order they're written in. + const resolveSlot = (slot: CardSlot) => + twMerge( + CARD_DEFAULT_CLASSES[slot], + resolvedTheme.classNames[slot], + resolvedProps.classNames[slot], + ); const displayValue = useMemo(() => { if (value == null) return null; - if (formatValue) return formatValue(value); - if (precision != null) return value.toFixed(precision); - return String(value); - }, [value, precision, formatValue]); + if (resolvedProps.formatValue) return resolvedProps.formatValue(value); + + if (resolvedProps.precision != null) + return value.toFixed(resolvedProps.precision); + + return String(value); + }, [value, resolvedProps.formatValue, resolvedProps.precision]); const displayLabel = useMemo(() => { if (timestamp == null) return null; - if (labelText) return labelText(timestamp); - const d = timestamp < 1e12 ? new Date(timestamp * 1000) : new Date(timestamp); - return `Updated ${d.toLocaleTimeString()}`; - }, [timestamp, labelText]); + if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); + + const d = + timestamp < 1e12 ? new Date(timestamp * 1000) : new Date(timestamp); + + return `Updated ${d.toLocaleTimeString()}`; + }, [timestamp, resolvedProps.labelText]); return (
- - {title} + + {resolvedProps.title} {loading ? ( @@ -172,22 +254,23 @@ const resolveSlot = (slot: CardSlot) =>
) : error ? ( - {error} + {error} ) : ( <> - + {displayValue} - {unit && ( + {resolvedProps.unit && ( - {unit} + {resolvedProps.unit} )} {displayLabel && ( - + {displayLabel} )} @@ -195,4 +278,4 @@ const resolveSlot = (slot: CardSlot) => )}
); -} \ No newline at end of file +} diff --git a/src/styles/base.css b/src/styles/base.css new file mode 100644 index 00000000..d08001bb --- /dev/null +++ b/src/styles/base.css @@ -0,0 +1,53 @@ +@import "tailwindcss"; + +/* Explicit @source directives, so Tailwind scans exactly the folders + that actually contain our class strings (CARD_DEFAULT_CLASSES, + lightTheme, darkTheme, and any future widget's defaults), rather + than relying purely on automatic content detection. Paths are + relative to THIS file's location (src/styles/base.css). */ +@source "../widgets/**/*.{ts,tsx}"; +@source "../themes/**/*.{ts,tsx}"; +@source "../common.ts"; + +/* ---------- Widget defaults ---------- */ + +.anedya-card { + container-type: inline-size; +container-name: anedya-card; + + --anedya-card-padding: 1rem; + + --anedya-card-title-size: .875rem; + --anedya-card-value-size: 2.25rem; + --anedya-card-unit-size: 1rem; + --anedya-card-label-size: .75rem; + + --anedya-card-gap: .5rem; +} + + +@container anedya-card(min-width: 320px) { + .anedya-card { + --anedya-card-padding: 1.25rem; + + --anedya-card-title-size: 1rem; + --anedya-card-value-size: 2.75rem; + --anedya-card-unit-size: 1.125rem; + --anedya-card-label-size: 0.875rem; + + --anedya-card-gap: 0.75rem; + } +} + +@container anedya-card(min-width: 420px) { + .anedya-card { + --anedya-card-padding: 1.5rem; + + --anedya-card-title-size: 1.125rem; + --anedya-card-value-size: 3.5rem; + --anedya-card-unit-size: 1.25rem; + --anedya-card-label-size: 1rem; + + --anedya-card-gap: 1rem; + } +} diff --git a/src/themes/defaultTheme.ts b/src/themes/defaultTheme.ts index bbf30711..2442c8c2 100644 --- a/src/themes/defaultTheme.ts +++ b/src/themes/defaultTheme.ts @@ -3,11 +3,21 @@ import { WidgetTheme } from "../types/root"; export const CARD_DEFAULT_CLASSES: Record = { - container: "flex flex-col gap-1 rounded-xl border p-4", - title: "text-sm font-medium", - value: "text-4xl font-bold", - unit: "text-[0.5em] font-normal ml-1", - label: "text-xs", + + title: + "text-[length:var(--anedya-card-title-size)] font-medium", + +value: + "text-[length:var(--anedya-card-value-size)] font-bold", + +unit: + "text-[length:var(--anedya-card-unit-size)]", + +label: + "text-[length:var(--anedya-card-label-size)]", + +container: + "flex flex-col border rounded-xl justify-center items-center p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" }; diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index e28aed1f..6bccb1c9 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -1,8 +1,11 @@ + + + import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; - +import "../../../dist/style.css"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; @@ -14,10 +17,11 @@ const client = anedya.newClient(config); const node = anedya.newNode(client, nodeId); /** - * A reusable theme that can be shared across multiple widgets. - * Only specify the classes you actually want to change. + * A reusable theme, shareable across every CardWidget instance in your + * app. Only specify the slots you actually want to change from the + * built-in default β€” anything omitted falls back to lightTheme/darkTheme. */ -const emeraldTheme = { +const emeraldTheme= { classNames: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", @@ -26,61 +30,140 @@ const emeraldTheme = { }, }; +const commonProps = { node, variable: "humidity" }; + export default function App() { return (
- {/* Default appearance */} + {/* ============================================================ + * 1. Default appearance β€” no theme, no classNames, no + * formatting props. Every fallback in the widget in one place. + * ============================================================ */} + + + {/* ============================================================ + * 2. theme β€” a reusable, shareable WidgetTheme object. Same + * effect across every widget instance that uses it. + * ============================================================ */} + + + {/* Built-in preset names also work directly: */} + + + {/* ============================================================ + * 3. classNames vs className β€” THE distinction to understand: + * + * - `classNames` (plural, an OBJECT): per-SLOT overrides. + * Keys are "container" | "title" | "value" | "unit" | "label" + * β€” lets you reach INSIDE the widget and style individual + * pieces independently. + * + * - `className` (singular, a STRING): the ordinary React + * convention β€” one class applied ONLY to the widget's + * outermost container element, same as you'd pass to any + * other component. It's merged (via twMerge) with whatever + * classNames.container already resolved to, not a + * replacement for it. + * + * This example uses BOTH at once so the difference is visible: + * className adds a shadow to the outer box, classNames.value/ + * classNames.title style two INNER pieces independently. + * ============================================================ */} - {/* Reusable theme */} + {/* ============================================================ + * 4. Plain CSS classes β€” classNames works with ANY class source, + * not just Tailwind. These reference plain hand-written CSS + * classes (e.g. defined in a .css file this app already imports). + * ============================================================ */} - {/* Per-instance overrides */} + {/* ============================================================ + * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` + * work exactly as they do anywhere else in your app, because + * classNames just forwards whatever string you write straight + * to `className`. This widget does NOT have its own custom + * breakpoint system β€” these prefixes are compiled by YOUR + * project's Tailwind config and respond to the BROWSER VIEWPORT, + * same as native Tailwind everywhere else. If your own + * tailwind.config.js customizes `theme.screens`, these prefixes + * automatically follow that customization too β€” nothing to + * configure on the widget's side. + * ============================================================ */} - {/* Plain CSS */} + {/* ============================================================ + * 6. formatValue / labelText β€” simple formatting hooks, distinct + * from styling. formatValue controls the displayed number's + * text; labelText controls the caption under it. + * ============================================================ */} `${v.toFixed(2)} % RH`} + labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} + /> + + {/* ============================================================ + * 7. onStyleChange β€” conditional class overrides driven by the + * RAW fetched data ({ value, timestamp }), always applied on top + * of everything else (theme, classNames, className). + * ============================================================ */} + { + if (!data) return; + + if (data.value > 80) { + return { + title: "High Humidity", + theme: "dark", + classNames: { + value: "text-red-500" + } + }; + } + + return { + title: "Humidity", + theme: "light" + }; + }} + /> + + {/* ============================================================ + * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, + * applied as inline styles on the container, independent of the + * whole classNames/theme system. + * ============================================================ */} +
); } \ No newline at end of file From 1daec005ee6d41cd56369981bbd13a2bf75af240 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Thu, 23 Jul 2026 09:14:52 +0530 Subject: [PATCH 21/66] build error ix --- dist/index.d.mts | 122 +++++++++++ dist/index.d.ts | 270 ++++++++++-------------- dist/index.js | 225 +++++++++++++++++++- dist/index.js.map | 1 - dist/index.mjs | 198 +++++++++++++++++- dist/index.mjs.map | 1 - dist/style.css | 2 +- dist/styles.css | 2 - package-lock.json | 375 +--------------------------------- package.json | 9 +- src/components/CardWidget.tsx | 18 +- src/themes/defaultTheme.ts | 3 +- test/my-app/src/App.jsx | 2 +- test/my-app/vite.config.js | 1 + tsup.config.ts | 3 +- 15 files changed, 681 insertions(+), 551 deletions(-) create mode 100644 dist/index.d.mts delete mode 100644 dist/index.js.map delete mode 100644 dist/index.mjs.map delete mode 100644 dist/styles.css diff --git a/dist/index.d.mts b/dist/index.d.mts new file mode 100644 index 00000000..37d78af8 --- /dev/null +++ b/dist/index.d.mts @@ -0,0 +1,122 @@ +import * as react_jsx_runtime from 'react/jsx-runtime'; + +type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; +type BuiltInTheme = "light" | "dark"; + +/** + * Generic per-slot class overrides. Every widget defines its own slot + * names (Card: container/title/value/unit/label, Chart: container/line/ + * axis/...) but they all share this same shape. + */ +type SlotClassNames = Partial>; +/** + * A widget theme is simply a reusable collection of Tailwind (or plain + * CSS) classes for a widget's slots. + * + * Themes are merged in three layers: + * + * built-in theme + * ↓ + * user theme + * ↓ + * widget classNames prop + * + * Later layers win via `twMerge`. + */ +interface WidgetTheme { + classNames: SlotClassNames; +} + +/** + * Every widget takes this shape as its base. Widget-specific props + * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * rather than repeating client/node/sizing/theme plumbing per widget. + * + * `node` is required directly (built by the consumer via + * `anedya.newNode(client, nodeId)`) rather than derived internally β€” + * keeps node/rate-limiting construction fully in the consumer's control, + * outside the widget. + */ +interface AnedyaWidgetBaseProps { + node: any; + variable: string; + /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ + from?: number; + to?: number; + limit?: number; + title?: string; + /** + * Optional theme for the widget. + * + * A theme is a reusable collection of classes for the widget's slots. + * It is merged with the widget's built-in defaults, while the + * `classNames` prop is applied afterwards for per-instance overrides. + */ + theme?: WidgetTheme | BuiltInTheme; + /** Applied to the widget's outermost element, on top of everything else. */ + className?: string; + width?: number; + height?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + aspectRatio?: number; +} + +type CardSlot = "container" | "title" | "value" | "unit" | "label"; +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +interface CardData { + value: number; + timestamp: number; +} +type CardWidgetUpdate = Partial>; +interface CardWidgetProps extends AnedyaWidgetBaseProps { + unit?: string; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + precision?: number; + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + classNames?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * classNames: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; +} +declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react_jsx_runtime.JSX.Element; + +export { CardWidget }; diff --git a/dist/index.d.ts b/dist/index.d.ts index ab7a4009..37d78af8 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -1,180 +1,122 @@ -import React, { CSSProperties } from 'react'; +import * as react_jsx_runtime from 'react/jsx-runtime'; -interface AnedyaClient { - tokenId: string; - tokenBytes: Uint8Array; - signatureVersionBytes: Uint8Array; - signatureVersion: string; - authorizationMode: string; - baseUrl: string; -} +type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; +type BuiltInTheme = "light" | "dark"; -interface InitOptions { - useGlobal?: boolean; - forceReinit?: boolean; - rateLimitMs?: number; -} /** - * Initialize the Anedya client and optionally store globally. + * Generic per-slot class overrides. Every widget defines its own slot + * names (Card: container/title/value/unit/label, Chart: container/line/ + * axis/...) but they all share this same shape. + */ +type SlotClassNames = Partial>; +/** + * A widget theme is simply a reusable collection of Tailwind (or plain + * CSS) classes for a widget's slots. * - * @returns client + * Themes are merged in three layers: + * + * built-in theme + * ↓ + * user theme + * ↓ + * widget classNames prop + * + * Later layers win via `twMerge`. */ -declare function anedyaClientInit(tokenId: string, token: string, options?: InitOptions): AnedyaClient; - -declare const defaultColorRanges: { - max: number; - color: string; -}[]; - -interface StyleSet { - container?: CSSProperties; - label?: CSSProperties; - value?: CSSProperties; - unit?: CSSProperties; -} -type UnitPosition$1 = "left" | "right" | "top" | "bottom"; -type UnitStyle$1 = "normal" | "subscript" | "superscript"; -interface DisplayTextResult$1 { - text: string; - unitText?: string; - position?: UnitPosition$1; - unitStyle?: UnitStyle$1; +interface WidgetTheme { + classNames: SlotClassNames; } -type DisplayTextFormatter$1 = (value: number, unit?: string) => DisplayTextResult$1; -interface LatestDataWidgetProps { - client: AnedyaClient; - nodeId: string; - variable: string; - title?: string; - unit?: string; - styles?: StyleSet; - colorRange?: typeof defaultColorRanges; - colorRangeCallback?: (value: number, defaultColor: string) => string; - fontFamily?: string; - displayText?: DisplayTextFormatter$1; - onStyleChange?: (value: number) => {}; -} -declare const LatestDataWidget: React.FC; -interface ChartDataPoint { - timestamp: number; - value: number; -} -type WidgetState$1 = { - value?: any; - loading?: boolean; - error?: string | null; -}; -interface ChartStyleSet { - container?: CSSProperties; - title?: CSSProperties; - tooltip?: CSSProperties; - axis?: CSSProperties; - chart?: { - strokeColor?: string; - strokeWidth?: number; - gradientColors?: [string, string]; - dotRadius?: number; - }; - fontFamily: string; -} -type StylesInput$1 = ChartStyleSet | ((state: WidgetState$1) => ChartStyleSet); -interface ChartWidgetProps { - client: any; - nodeId: string; +/** + * Every widget takes this shape as its base. Widget-specific props + * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * rather than repeating client/node/sizing/theme plumbing per widget. + * + * `node` is required directly (built by the consumer via + * `anedya.newNode(client, nodeId)`) rather than derived internally β€” + * keeps node/rate-limiting construction fully in the consumer's control, + * outside the widget. + */ +interface AnedyaWidgetBaseProps { + node: any; variable: string; - from: number; - to: number; + /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ + from?: number; + to?: number; limit?: number; title?: string; - styles?: StylesInput$1; - tooltipFormatter?: (d: ChartDataPoint) => string; - tickCount?: number; - tickFormatter?: (d: Date) => string; - xTickFormat?: string | ((d: Date) => string); - yTickFormat?: string | ((v: number) => string); - tooltipFormat?: string | ((d: ChartDataPoint) => string); - onStyleChange?: (data: ChartDataPoint[]) => {}; + /** + * Optional theme for the widget. + * + * A theme is a reusable collection of classes for the widget's slots. + * It is merged with the widget's built-in defaults, while the + * `classNames` prop is applied afterwards for per-instance overrides. + */ + theme?: WidgetTheme | BuiltInTheme; + /** Applied to the widget's outermost element, on top of everything else. */ + className?: string; + width?: number; + height?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + aspectRatio?: number; } -declare const ChartWidget: React.FC; -interface GaugeArcStyle { - trackColor?: string; - progressColor?: string; - progressStroke?: string; - fontSize?: string | number; - fontFamily?: string; -} -interface Zone { - from: number; - to: number; - color: string; -} -type WidgetState = { - value?: any; - loading?: boolean; - error?: string | null; -}; -interface GaugeStyleSet { - container?: CSSProperties; - label?: CSSProperties; - value?: CSSProperties; - unit?: CSSProperties; - subtitle?: CSSProperties; - arc?: GaugeArcStyle; - fontFamily?: string; -} -type StylesInput = GaugeStyleSet | ((state: WidgetState) => GaugeStyleSet); -interface GaugeMetrics { - maxRadius: number; - valueAngleDeg: number; - valueAngleRad: number; - startAngleDeg: number; - endAngleDeg: number; - innerRadius: number; - outerRadius: number; - cx: number; - cy: number; +type CardSlot = "container" | "title" | "value" | "unit" | "label"; +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +interface CardData { + value: number; + timestamp: number; } -interface GaugeWidgetProps { - client: any; - nodeId: string; - variable: string; - min?: number; - max?: number; - startAngleDeg?: number; - endAngleDeg?: number; - thickness?: number; - zones?: Zone[]; - showNeedle?: boolean; - needleColor?: string; - needleWidth?: number; - title?: string; - subtitle?: string; - styles?: StylesInput; - disabled?: boolean; - tickCount?: number; +type CardWidgetUpdate = Partial>; +interface CardWidgetProps extends AnedyaWidgetBaseProps { unit?: string; - uomOffset?: number; - labelOffset?: number; - onMetrics?: (metrics: GaugeMetrics) => void; - valueText?: (opts: { - value?: number; - valueMin: number; - valueMax: number; - }) => string; - onStyleChange?: (value: number) => {}; - displayText?: DisplayTextFormatter; -} -type UnitPosition = "left" | "right" | "top" | "bottom"; -type UnitStyle = "normal" | "subscript" | "superscript"; -interface DisplayTextResult { - text: string; - unitText?: string; - position?: UnitPosition; - unitStyle?: UnitStyle; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + precision?: number; + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + classNames?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * classNames: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; } -type DisplayTextFormatter = (value: number, unit?: string) => DisplayTextResult; -declare const LatestDataGauge: React.FC; +declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react_jsx_runtime.JSX.Element; -export { ChartWidget, LatestDataGauge, LatestDataWidget, anedyaClientInit }; +export { CardWidget }; diff --git a/dist/index.js b/dist/index.js index f503c603..afcd91ab 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,2 +1,223 @@ -"use strict";var t=require("react/jsx-runtime"),e=require("react");function n(t){return t&&t.__esModule?t:{default:t}}var r=n(e),i=function(t,e){return i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},i(t,e)};function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var a=function(){return a=Object.assign||function(t){for(var e,n=1,r=arguments.length;n0&&i[i.length-1])||6!==u[0]&&2!==u[0])){o=0;continue}if(3===u[0]&&(!i||u[1]>i[0]&&u[1]{try{let r=(new TextEncoder).encode(JSON.stringify(t)),i=await crypto.subtle.digest("SHA-256",r),o=new Uint8Array(i),a=new Uint8Array(8);new DataView(a.buffer).setBigUint64(0,BigInt(n),!1);let u=new Uint8Array(o.length+a.length+e.signatureVersionBytes.length+e.tokenBytes.length);u.set(o,0),u.set(a,o.length),u.set(e.signatureVersionBytes,o.length+a.length),u.set(e.tokenBytes,o.length+a.length+e.signatureVersionBytes.length);let s=await crypto.subtle.digest("SHA-256",u);return Array.from(new Uint8Array(s)).map(t=>t.toString(16).padStart(2,"0")).join("")}catch(t){console.log(t)}},S=class{#t;#e;#n;constructor(t,e){let{baseUrl:n,tokenId:r,tokenBytes:i,signatureVersionBytes:o,signatureVersion:a,authorizationMode:u}=t;this.#t=e,this.#e=n,this.#n={tokenId:r,tokenBytes:i,signatureVersion:a,signatureVersionBytes:o,authorizationMode:u}}getNodeId(){return this.#t}async getData(t){return await(async(t,e,n,r)=>{let i=`${t}/data/getData`,o={nodes:n,variable:r.variable,from:Math.floor(r.from/1e3),to:Math.floor(r.to/1e3),limit:r.limit,order:r.order},a=Math.floor(Date.now()/1e3),u=await M(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),s=new g;try{let t=await r.json();if(s.isSuccess=t.success,s.error.errorMessage=t.error,s.error.reasonCode=t.reasonCode,s.isDataAvailable=!1,s.data=null,t.success){let e=t.data;null==e||null==e||0===Object.keys(e).length?s.isDataAvailable=!1:1===n.length?(e=e[n.toString()],s.data=e,s.isDataAvailable=!0):(s.data=e,s.isDataAvailable=!0)}return s.count=t.count,s.startTime=t.startTime,s.endTime=t.endTime,s}catch{return s.isSuccess=!1,s.error.reasonCode=r.status.toString(),s.error.errorMessage=r.statusText,s}}catch(t){throw console.error("Error during Get data request:",t),t}})(this.#e,this.#n,[this.#t],t)}async getLatestData(t){let e={variable:t};return await(async(t,e,n,r)=>{let i=`${t}/data/latest`,o={nodes:n,variable:r.variable},a=Math.floor(Date.now()/1e3),u=await M(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),s=new y;try{let t=await r.json();if(s.isSuccess=t.success,s.error.errorMessage=t.error,s.error.reasonCode=t.reasonCode,s.isDataAvailable=!1,s.data=null,t.success){let e=t.data;null==e||null==e||0===Object.keys(e).length?s.isDataAvailable=!1:1===n.length?(e=e[n.toString()],s.data=e,s.isDataAvailable=!0):(s.data=e,s.isDataAvailable=!0)}return s}catch{return s.isSuccess=!1,s.error.reasonCode=r.status.toString(),s.error.errorMessage=r.statusText,s}}catch(t){throw console.error("Error during get latest data request:",t),t}})(this.#e,this.#n,[this.#t],e)}async setKey(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/setValue`;i="node"===r.namespace.scope?n[0]:r.namespace.id;let a={namespace:{scope:r.namespace.scope,id:i},key:r.key,value:r.value,type:r.type},u=Math.floor(Date.now()/1e3),s=await M(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":s,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new v;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during set key: ",t),t}})(this.#e,this.#n,[this.#t],t)}async getKey(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/getValue`;i="node"===r.namespace.scope?n[0]:r.namespace.id;let a={namespace:{scope:r.namespace.scope,id:i},key:r.key},u=Math.floor(Date.now()/1e3),s=await M(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":s,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new m;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.namespace=t.namespace,r.key=t.key,r.value=t.value,r.type=t.type,r.size=t.size,r.modified=t.modified,r.created=t.created,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during get key request: ",t),t}})(this.#e,this.#n,[this.#t],t)}async deleteKey(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/delete`;i="node"===r.namespace.scope?n[0]:r.namespace.id;let a={namespace:{scope:r.namespace.scope,id:i},key:r.key},u=Math.floor(Date.now()/1e3),s=await M(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":s,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new x;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during fetch operation:",t),t}})(this.#e,this.#n,[this.#t],t)}async scanKeys(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/scan`;i="node"===r.filter.namespace.scope?n[0]:r.filter.namespace.id;let a={filter:{namespace:{scope:r.filter.namespace.scope,id:i}},orderby:r.orderby,order:r.order,limit:r.limit,offset:r.offset},u=Math.floor(Date.now()/1e3),s=await M(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":s,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new w;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.count=t.count,r.totalCount=t.totalCount,r.data=t.data,r.next=t.next,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during scan vs operation: ",t),t}})(this.#e,this.#n,[this.#t],t)}async getDeviceStatus(t){return await(async(t,e,n,r)=>{let i=`${t}/health/status`,o={nodes:n,lastContactThreshold:r},a=Math.floor(Date.now()/1e3),u=await M(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),s=new b;try{let t=await r.json();return s.isSuccess=t.success,s.error.errorMessage=t.error,s.error.reasonCode=t.reasonCode,s.isSuccess&&(1===n.length?s.data=t.data[n[0]]:s.data=t.data),s}catch{return s.isSuccess=!1,s.error.errorMessage=r.statusText,s.error.reasonCode=r.status.toString(),s}}catch(t){throw console.error("Error during fetch operation:",t),t}})(this.#e,this.#n,[this.#t],t)}async getSnapshot(t){return await(async(t,e,n,r)=>{let i=`${t}/data/snapshot`,o={nodes:n,time:r?.time,variable:r?.variable},a=Math.floor(Date.now()/1e3),u=await M(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),s=new _;try{let t=await r.json();return s.isSuccess=t.success,s.error.errorMessage=t.error,s.error.reasonCode=t.reasonCode,s.isSuccess&&(1===n.length?s.data=t.data.filter(t=>t.node===n[0]):s.data=t.data,s.count=t.count),s}catch{return s.isSuccess=!1,s.error.errorMessage=r.statusText,s.error.reasonCode=r.status.toString(),s}}catch(t){throw console.error("Error during fetch operation:",t),t}})(this.#e,this.#n,[this.#t],t)}},A=class{NewConfig(t,e){return new d(t,e)}NewClient(t){return new p(t)}NewNode(t,e){return new S(t,e)}},T=((h=T||{}).GLOBAL="global",h.NODE="node",h),C=((f=C||{}).STRING="string",f.BINARY="binary",f.FLOAT="float",f.BOOLEAN="boolean",f),k=null,N=new Map;function j(t,e,n){var r=n.filter(function(t){return void 0===e[t]});if(0!==r.length){var i="[".concat(t,"] Missing required prop(s): ").concat(r.join(", "));console.error(i)}}var D=[{max:40,color:"#008000"},{max:100,color:"#FFA500"},{max:1/0,color:"#FF2C2C"}],F="Roboto, sans-serif",$={container:{width:400,height:250,padding:2,margin:0,display:"flex",flexDirection:"column",justifyContent:"flex-start",alignItems:"center",borderRadius:10,boxSizing:"border-box",background:"rgb(248, 249, 250)",border:"1px solid rgba(211, 216, 220, 1)",fontFamily:F,color:"#000000",gap:2,textAlign:"center"},label:{fontWeight:500,color:"#000000",fontFamily:F},value:{fontWeight:700,color:"#000000",fontFamily:F},unit:{fontWeight:400,color:"#000000",fontFamily:F}},E=function(t){return t?Array.isArray(t)?Object.assign.apply(Object,c([{}],t,!1)):"function"==typeof t?t({}):t:{}},U=function(n){var r,i,o,u,c,f,h,d,p,g,y,v,m,x,w,b,_=n.client,M=n.nodeId,S=n.variable,A=n.title,T=void 0===A?"Latest Data":A,C=n.unit,k=void 0===C?"":C,N=n.styles,F=void 0===N?{}:N,U=n.displayText,R=n.colorRange,z=n.colorRangeCallback,I=n.onStyleChange;j("LatestDataWidget",{client:_,nodeId:M,variable:S},["client","nodeId","variable"]);var O=e.useState(null),P=O[0],L=O[1],Y=e.useState(!1),V=Y[0],H=Y[1],X=e.useState(null),q=X[0],B=X[1],W=e.useState(null),J=W[0],G=W[1],Z=e.useRef(!1),Q=e.useRef(0),K=e.useRef(!1);e.useRef(0);var tt={data:P,loading:V,error:q},et=e.useState({}),nt=et[0],rt=et[1],it="function"==typeof F?F(tt):F||{},ot={container:a(a({},it.container),null==nt?void 0:nt.container),label:a(a({},it.label),null==nt?void 0:nt.label),value:a(a({},it.value),null==nt?void 0:nt.value),unit:a(a({},it.unit),null==nt?void 0:nt.unit),fontFamily:null!==(r=null==nt?void 0:nt.fontFamily)&&void 0!==r?r:it.fontFamily},at=U?U(Number(P),k):{text:String(null!=P?P:""),unitText:k,position:"right",unitStyle:"normal"};e.useEffect(function(){if(_&&M){var t=_._anedya.NewNode(_,M);G(t)}},[_,M]),e.useEffect(function(){if(K.current=!0,J){return s(void 0,void 0,void 0,function(){var t,e,n,r;return l(this,function(i){switch(i.label){case 0:if(Z.current||Q.current>=3)return console.log("!node:",J),console.log("isFetchingRef.current:",Z.current),console.log("failureCountRef.current:",Q.current),[2];Z.current=!0,i.label=1;case 1:return i.trys.push([1,3,4,5]),H(!0),B(null),[4,J.getLatestData(S)];case 2:return t=i.sent(),K.current?(t.isSuccess&&t.isDataAvailable?(L(null===(n=t.data)||void 0===n?void 0:n.value),B("")):(L(null),console.error("error fetching data:",t.error),B(t.error.errorMessage)),Q.current=0,[3,5]):[2];case 3:return e=i.sent(),K.current?(console.error("Error fetching latest data:",e),L(null),B(null!==(r=null==e?void 0:e.message)&&void 0!==r?r:"Failed to fetch data"),Q.current+=1,[3,5]):[2];case 4:return K.current?(H(!1),Z.current=!1,[7]):[2];case 5:return[2]}})}),function(){K.current=!1}}},[J,S]),e.useEffect(function(){if("function"==typeof I){var t=I(P);t&&"object"==typeof t&&rt(t)}},[P]);var ut=E(null==ot?void 0:ot.container),st=E(null==ot?void 0:ot.label),lt=E(null==ot?void 0:ot.value),ct=E(null==ot?void 0:ot.unit),ft=$.container,ht=null!==(i=ut.width)&&void 0!==i?i:ft.width,dt=null!==(o=ut.height)&&void 0!==o?o:ft.height,pt=.15*Math.min(Number(ht),Number(dt)),gt=null!==(c=null===(u=null==ot?void 0:ot.label)||void 0===u?void 0:u.fontSize)&&void 0!==c?c:.6*pt,yt=null!==(h=null===(f=null==ot?void 0:ot.value)||void 0===f?void 0:f.fontSize)&&void 0!==h?h:3*pt,vt=null!==(p=null===(d=null==ot?void 0:ot.unit)||void 0===d?void 0:d.fontSize)&&void 0!==p?p:.8*pt,mt=null!==(g=null==ot?void 0:ot.fontFamily)&&void 0!==g?g:"Roboto",xt=null!==(y=st.fontFamily)&&void 0!==y?y:mt,wt=null!==(v=lt.fontFamily)&&void 0!==v?v:mt,bt=null!==(m=ct.fontFamily)&&void 0!==m?m:mt,_t=null!==(x=ut.gap)&&void 0!==x?x:.2*pt,Mt=null!=R?R:D,St=function(t,e){var n;void 0===e&&(e=D);var r=e.find(function(e){return t<=e.max});return null!==(n=null==r?void 0:r.color)&&void 0!==n?n:"#333"}(null!==(w=Number(P))&&void 0!==w?w:0,Mt);z&&(St=z(null!==(b=Number(P))&&void 0!==b?b:0,St));var At=a(a(a({},$.container),ut),{gap:_t}),Tt=a(a(a(a({},$.label),{fontSize:gt}),st),{fontFamily:xt}),Ct=a(a(a(a({},$.value),{fontSize:yt,color:St}),lt),{fontFamily:wt}),kt=a(a(a(a({},$.unit),{fontSize:vt}),ct),{fontFamily:bt}),Nt=function(e,n){switch(n){case"superscript":return t.jsx("sup",{children:e});case"subscript":return t.jsx("sub",{children:e});default:return t.jsx("span",{children:e})}};return t.jsxs("div",{style:a({},At),children:[T&&t.jsx("h2",{style:Tt,children:T}),V?t.jsx("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",height:"100%"},children:t.jsx("div",{className:"spinner",style:{width:.3*Math.min(Number(ht),Number(dt)),height:.3*Math.min(Number(ht),Number(dt))}})}):q?t.jsx("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:t.jsx("div",{style:{background:"rgba(255, 0, 0, 0.15)",border:"1px solid rgba(255, 0, 0, 0.6)",boxShadow:"rgba(149, 157, 165, 0.2) 0px 8px 24px",color:"rgba(255, 0, 0, 0.6)",textAlign:"center",borderRadius:"5px",padding:"5px"},children:q})}):P?t.jsx(t.Fragment,{children:t.jsxs("div",{style:a(a({},Ct),{display:"flex",flexDirection:"top"===at.position||"bottom"===at.position?"column":"row",alignItems:"center",justifyContent:"center",gap:4}),children:[at.unitText&&"left"===at.position&&t.jsx("div",{style:kt,children:Nt(at.unitText,at.unitStyle)}),t.jsx("div",{children:at.text}),at.unitText&&"right"===at.position&&t.jsx("div",{style:kt,children:Nt(at.unitText,at.unitStyle)}),at.unitText&&"top"===at.position&&t.jsx("div",{style:a(a({},kt),{order:-1}),children:Nt(at.unitText,at.unitStyle)}),at.unitText&&"bottom"===at.position&&t.jsx("div",{style:a(a({},kt),{order:1}),children:Nt(at.unitText,at.unitStyle)})]})}):t.jsx("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:t.jsx("div",{style:{color:"#757575",textAlign:"center",borderRadius:"5px",padding:"5px"},children:"No data available"})})]})},R=r.default.memo(function(e){var n=e.client,r=e.nodeId,i=e.variable,o=e.title,a=e.unit,u=e.styles,s=void 0===u?{}:u,l=e.colorRange,c=e.colorRangeCallback,f=e.displayText,h=e.onStyleChange;return t.jsx(t.Fragment,{children:t.jsx(U,{displayText:f,client:n,nodeId:r,variable:i,title:o,unit:a,styles:s,colorRange:l,colorRangeCallback:c,onStyleChange:h})})},function(t,e){return JSON.stringify(t)===JSON.stringify(e)});function z(t,e){return null==t||null==e?NaN:te?1:t>=e?0:NaN}function I(t,e){return null==t||null==e?NaN:et?1:e>=t?0:NaN}function O(t){let e,n,r;function i(t,r,i=0,o=t.length){if(i>>1;n(t[e],r)<0?i=e+1:o=e}while(iz(t(e),n),r=(e,n)=>t(e)-n):(e=t===z||t===I?t:P,n=t,r=t),{left:i,center:function(t,e,n=0,o=t.length){const a=i(t,e,n,o-1);return a>n&&r(t[a-1],e)>-r(t[a],e)?a-1:a},right:function(t,r,i=0,o=t.length){if(i>>1;n(t[e],r)<=0?i=e+1:o=e}while(i=Y?10:o>=V?5:o>=H?2:1;let u,s,l;return i<0?(l=Math.pow(10,-i)/a,u=Math.round(t*l),s=Math.round(e*l),u/le&&--s,l=-l):(l=Math.pow(10,i)*a,u=Math.round(t/l),s=Math.round(e/l),u*le&&--s),s+t(e)}function K(t,e){return e=Math.max(0,t.bandwidth()-2*e)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function tt(){return!this.__axis}function et(t,e){var n=[],r=null,i=null,o=6,a=6,u=3,s="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,l=1===t||4===t?-1:1,c=4===t||2===t?"x":"y",f=1===t||3===t?G:Z;function h(h){var d=null==r?e.ticks?e.ticks.apply(e,n):e.domain():r,p=null==i?e.tickFormat?e.tickFormat.apply(e,n):W:i,g=Math.max(o,0)+u,y=e.range(),v=+y[0]+s,m=+y[y.length-1]+s,x=(e.bandwidth?K:Q)(e.copy(),s),w=h.selection?h.selection():h,b=w.selectAll(".domain").data([null]),_=w.selectAll(".tick").data(d,e).order(),M=_.exit(),S=_.enter().append("g").attr("class","tick"),A=_.select("line"),T=_.select("text");b=b.merge(b.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),_=_.merge(S),A=A.merge(S.append("line").attr("stroke","currentColor").attr(c+"2",l*o)),T=T.merge(S.append("text").attr("fill","currentColor").attr(c,l*g).attr("dy",1===t?"0em":3===t?"0.71em":"0.32em")),h!==w&&(b=b.transition(h),_=_.transition(h),A=A.transition(h),T=T.transition(h),M=M.transition(h).attr("opacity",J).attr("transform",function(t){return isFinite(t=x(t))?f(t+s):this.getAttribute("transform")}),S.attr("opacity",J).attr("transform",function(t){var e=this.parentNode.__axis;return f((e&&isFinite(e=e(t))?e:x(t))+s)})),M.remove(),b.attr("d",4===t||2===t?a?"M"+l*a+","+v+"H"+s+"V"+m+"H"+l*a:"M"+s+","+v+"V"+m:a?"M"+v+","+l*a+"V"+s+"H"+m+"V"+l*a:"M"+v+","+s+"H"+m),_.attr("opacity",1).attr("transform",function(t){return f(x(t)+s)}),A.attr(c+"2",l*o),T.attr(c,l*g).text(p),w.filter(tt).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",2===t?"start":4===t?"end":"middle"),w.each(function(){this.__axis=x})}return h.scale=function(t){return arguments.length?(e=t,h):e},h.ticks=function(){return n=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(n=null==t?[]:Array.from(t),h):n.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(s=+t,h):s},h}var nt={value:()=>{}};function rt(){for(var t,e=0,n=arguments.length,r={};e=0&&(e=t.slice(n+1),t=t.slice(0,n)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=e&&"function"!=typeof e)throw new Error("invalid callback: "+e);for(;++a0)for(var n,r,i=new Array(n),o=0;o=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),st.hasOwnProperty(e)?{space:st[e],local:t}:t}function ct(t){return function(){var e=this.ownerDocument,n=this.namespaceURI;return n===ut&&e.documentElement.namespaceURI===ut?e.createElement(t):e.createElementNS(n,t)}}function ft(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function ht(t){var e=lt(t);return(e.local?ft:ct)(e)}function dt(){}function pt(t){return null==t?dt:function(){return this.querySelector(t)}}function gt(){return[]}function yt(t){return null==t?gt:function(){return this.querySelectorAll(t)}}function vt(t){return function(){return function(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}(t.apply(this,arguments))}}function mt(t){return function(){return this.matches(t)}}function xt(t){return function(e){return e.matches(t)}}var wt=Array.prototype.find;function bt(){return this.firstElementChild}var _t=Array.prototype.filter;function Mt(){return Array.from(this.children)}function St(t){return new Array(t.length)}function At(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function Tt(t,e,n,r,i,o){for(var a,u=0,s=e.length,l=o.length;ue?1:t>=e?0:NaN}function Dt(t){return function(){this.removeAttribute(t)}}function Ft(t){return function(){this.removeAttributeNS(t.space,t.local)}}function $t(t,e){return function(){this.setAttribute(t,e)}}function Et(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function Ut(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function Rt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function zt(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function It(t){return function(){this.style.removeProperty(t)}}function Ot(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Pt(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Lt(t,e){return t.style.getPropertyValue(e)||zt(t).getComputedStyle(t,null).getPropertyValue(e)}function Yt(t){return function(){delete this[t]}}function Vt(t,e){return function(){this[t]=e}}function Ht(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function Xt(t){return t.trim().split(/^|\s+/)}function qt(t){return t.classList||new Bt(t)}function Bt(t){this._node=t,this._names=Xt(t.getAttribute("class")||"")}function Wt(t,e){for(var n=qt(t),r=-1,i=e.length;++r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var ye=[null];function ve(t,e){this._groups=t,this._parents=e}function me(){return new ve([[document.documentElement]],ye)}function xe(t){return"string"==typeof t?new ve([[document.querySelector(t)]],[document.documentElement]):new ve([[t]],ye)}function we(t,e,n){t.prototype=e.prototype=n,n.constructor=t}function be(t,e){var n=Object.create(t.prototype);for(var r in e)n[r]=e[r];return n}function _e(){}ve.prototype=me.prototype={constructor:ve,select:function(t){"function"!=typeof t&&(t=pt(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=w&&(w=x+1);!(m=y[w])&&++w=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=jt);for(var n=this._groups,r=n.length,i=new Array(r),o=0;o1?this.each((null==e?It:"function"==typeof e?Pt:Ot)(t,e,null==n?"":n)):Lt(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?Yt:"function"==typeof e?Ht:Vt)(t,e)):this.node()[t]},classed:function(t,e){var n=Xt(t+"");if(arguments.length<2){for(var r=qt(this.node()),i=-1,o=n.length;++i=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=e?he:fe,r=0;r>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Pe(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Pe(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=Ne.exec(t))?new Ye(e[1],e[2],e[3],1):(e=je.exec(t))?new Ye(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=De.exec(t))?Pe(e[1],e[2],e[3],e[4]):(e=Fe.exec(t))?Pe(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=$e.exec(t))?We(e[1],e[2]/100,e[3]/100,1):(e=Ee.exec(t))?We(e[1],e[2]/100,e[3]/100,e[4]):Ue.hasOwnProperty(t)?Oe(Ue[t]):"transparent"===t?new Ye(NaN,NaN,NaN,0):null}function Oe(t){return new Ye(t>>16&255,t>>8&255,255&t,1)}function Pe(t,e,n,r){return r<=0&&(t=e=n=NaN),new Ye(t,e,n,r)}function Le(t,e,n,r){return 1===arguments.length?((i=t)instanceof _e||(i=Ie(i)),i?new Ye((i=i.rgb()).r,i.g,i.b,i.opacity):new Ye):new Ye(t,e,n,null==r?1:r);var i}function Ye(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function Ve(){return`#${Be(this.r)}${Be(this.g)}${Be(this.b)}`}function He(){const t=Xe(this.opacity);return`${1===t?"rgb(":"rgba("}${qe(this.r)}, ${qe(this.g)}, ${qe(this.b)}${1===t?")":`, ${t})`}`}function Xe(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function qe(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function Be(t){return((t=qe(t))<16?"0":"")+t.toString(16)}function We(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new Ge(t,e,n,r)}function Je(t){if(t instanceof Ge)return new Ge(t.h,t.s,t.l,t.opacity);if(t instanceof _e||(t=Ie(t)),!t)return new Ge;if(t instanceof Ge)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),o=Math.max(e,n,r),a=NaN,u=o-i,s=(o+i)/2;return u?(a=e===o?(n-r)/u+6*(n0&&s<1?0:a,new Ge(a,u,s,t.opacity)}function Ge(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function Ze(t){return(t=(t||0)%360)<0?t+360:t}function Qe(t){return Math.max(0,Math.min(1,t||0))}function Ke(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}we(_e,Ie,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Re,formatHex:Re,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return Je(this).formatHsl()},formatRgb:ze,toString:ze}),we(Ye,Le,be(_e,{brighter(t){return t=null==t?Se:Math.pow(Se,t),new Ye(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?Me:Math.pow(Me,t),new Ye(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new Ye(qe(this.r),qe(this.g),qe(this.b),Xe(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ve,formatHex:Ve,formatHex8:function(){return`#${Be(this.r)}${Be(this.g)}${Be(this.b)}${Be(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:He,toString:He})),we(Ge,function(t,e,n,r){return 1===arguments.length?Je(t):new Ge(t,e,n,null==r?1:r)},be(_e,{brighter(t){return t=null==t?Se:Math.pow(Se,t),new Ge(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?Me:Math.pow(Me,t),new Ge(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new Ye(Ke(t>=240?t-240:t+120,i,r),Ke(t,i,r),Ke(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new Ge(Ze(this.h),Qe(this.s),Qe(this.l),Xe(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Xe(this.opacity);return`${1===t?"hsl(":"hsla("}${Ze(this.h)}, ${100*Qe(this.s)}%, ${100*Qe(this.l)}%${1===t?")":`, ${t})`}`}}));var tn=t=>()=>t;function en(t){return 1===(t=+t)?nn:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):tn(isNaN(e)?n:e)}}function nn(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):tn(isNaN(t)?e:t)}var rn=function t(e){var n=en(e);function r(t,e){var r=n((t=Le(t)).r,(e=Le(e)).r),i=n(t.g,e.g),o=n(t.b,e.b),a=nn(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=o(e),t.opacity=a(e),t+""}}return r.gamma=t,r}(1);function on(t,e){e||(e=[]);var n,r=t?Math.min(e.length,t.length):0,i=e.slice();return function(o){for(n=0;no&&(i=e.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(n=n[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,s.push({i:a,x:sn(n,r)})),o=fn.lastIndex;return o180?e+=360:e-t>180&&(t+=360),o.push({i:n.push(i(n)+"rotate(",null,r)-2,x:sn(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(o.rotate,a.rotate,u,s),function(t,e,n,o){t!==e?o.push({i:n.push(i(n)+"skewX(",null,r)-2,x:sn(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(o.skewX,a.skewX,u,s),function(t,e,n,r,o,a){if(t!==n||e!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:sn(t,n)},{i:u-2,x:sn(e,r)})}else 1===n&&1===r||o.push(i(o)+"scale("+n+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,s),o=a=null,function(t){for(var e,n=-1,r=s.length;++n=0&&e._call.call(void 0,t),e=e._next;--Sn}()}finally{Sn=0,function(){var t,e,n=wn,r=1/0;for(;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:wn=e);bn=t,In(r)}(),kn=0}}function zn(){var t=jn.now(),e=t-Cn;e>1e3&&(Nn-=e,Cn=t)}function In(t){Sn||(An&&(An=clearTimeout(An)),t-kn>24?(t<1/0&&(An=setTimeout(Rn,t-jn.now()-Nn)),Tn&&(Tn=clearInterval(Tn))):(Tn||(Cn=jn.now(),Tn=setInterval(zn,1e3)),Sn=1,Dn(Rn)))}function On(t,e,n){var r=new En;return e=null==e?0:+e,r.restart(n=>{r.stop(),t(n+e)},e,n),r}En.prototype=Un.prototype={constructor:En,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?Fn():+n)+(null==e?0:+e),this._next||bn===this||(bn?bn._next=this:wn=this,bn=this),this._call=t,this._time=n,In()},stop:function(){this._call&&(this._call=null,this._time=1/0,In())}};var Pn=rt("start","end","cancel","interrupt"),Ln=[];function Yn(t,e,n,r,i,o){var a=t.__transition;if(a){if(n in a)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function o(t){n.state=1,n.timer.restart(a,n.delay,n.time),n.delay<=t&&a(t-n.delay)}function a(o){var l,c,f,h;if(1!==n.state)return s();for(l in i)if((h=i[l]).name===n.name){if(3===h.state)return On(a);4===h.state?(h.state=6,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[l]):+l0)throw new Error("too late; already scheduled");return n}function Hn(t,e){var n=Xn(t,e);if(n.state>3)throw new Error("too late; already running");return n}function Xn(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function qn(t,e){var n,r;return function(){var i=Hn(this,t),o=i.tween;if(o!==n)for(var a=0,u=(r=n=o).length;a=0&&(t=t.slice(0,e)),!t||"start"===t})}(e)?Vn:Hn;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(e,n),a.on=i}}(n,t,e))},attr:function(t,e){var n=lt(t),r="transform"===n?Mn:Jn;return this.attrTween(t,"function"==typeof e?(n.local?er:tr)(n,r,Wn(this,"attr."+t,e)):null==e?(n.local?Zn:Gn)(n):(n.local?Kn:Qn)(n,r,e))},attrTween:function(t,e){var n="attr."+t;if(arguments.length<2)return(n=this.tween(n))&&n._value;if(null==e)return this.tween(n,null);if("function"!=typeof e)throw new Error;var r=lt(t);return this.tween(n,(r.local?nr:rr)(r,e))},style:function(t,e,n){var r="transform"==(t+="")?_n:Jn;return null==e?this.styleTween(t,function(t,e){var n,r,i;return function(){var o=Lt(this,t),a=(this.style.removeProperty(t),Lt(this,t));return o===a?null:o===n&&a===r?i:i=e(n=o,r=a)}}(t,r)).on("end.style."+t,lr(t)):"function"==typeof e?this.styleTween(t,function(t,e,n){var r,i,o;return function(){var a=Lt(this,t),u=n(this),s=u+"";return null==u&&(this.style.removeProperty(t),s=u=Lt(this,t)),a===s?null:a===r&&s===i?o:(i=s,o=e(r=a,u))}}(t,r,Wn(this,"style."+t,e))).each(function(t,e){var n,r,i,o,a="style."+e,u="end."+a;return function(){var s=Hn(this,t),l=s.on,c=null==s.value[a]?o||(o=lr(e)):void 0;l===n&&i===c||(r=(n=l).copy()).on(u,i=c),s.on=r}}(this._id,t)):this.styleTween(t,function(t,e,n){var r,i,o=n+"";return function(){var a=Lt(this,t);return a===o?null:a===r?i:i=e(r=a,n)}}(t,r,e),n).on("end.style."+t,null)},styleTween:function(t,e,n){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==e)return this.tween(r,null);if("function"!=typeof e)throw new Error;return this.tween(r,function(t,e,n){var r,i;function o(){var o=e.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}(t,o,n)),r}return o._value=e,o}(t,e,null==n?"":n))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var e=t(this);this.textContent=null==e?"":e}}(Wn(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var e="text";if(arguments.length<1)return(e=this.tween(e))&&e._value;if(null==t)return this.tween(e,null);if("function"!=typeof t)throw new Error;return this.tween(e,function(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&function(t){return function(e){this.textContent=t.call(this,e)}}(r)),e}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var e=this.parentNode;for(var n in this.__transition)if(+n!==t)return;e&&e.removeChild(this)}}(this._id))},tween:function(t,e){var n=this._id;if(t+="",arguments.length<2){for(var r,i=Xn(this.node(),n).tween,o=0,a=i.length;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete o[i]):a=!1;a&&delete t.__transition}}(this,t)})},me.prototype.transition=function(t){var e,n;t instanceof fr?(e=t._id,t=t._name):(e=hr(),(n=pr).time=Fn(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o=0))throw new Error(`invalid digits: ${t}`);if(e>15)return wr;const n=10**e;return function(t){this._+=t[0];for(let e=1,r=t.length;emr)if(Math.abs(c*u-s*l)>mr&&i){let h=n-o,d=r-a,p=u*u+s*s,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(f),m=i*Math.tan((yr-Math.acos((p+f-g)/(2*y*v)))/2),x=m/v,w=m/y;Math.abs(x-1)>mr&&this._append`L${t+x*l},${e+x*c}`,this._append`A${i},${i},0,0,${+(c*h>l*d)},${this._x1=t+w*u},${this._y1=e+w*s}`}else this._append`L${this._x1=t},${this._y1=e}`;else;}arc(t,e,n,r,i,o){if(t=+t,e=+e,o=!!o,(n=+n)<0)throw new Error(`negative radius: ${n}`);let a=n*Math.cos(r),u=n*Math.sin(r),s=t+a,l=e+u,c=1^o,f=o?r-i:i-r;null===this._x1?this._append`M${s},${l}`:(Math.abs(this._x1-s)>mr||Math.abs(this._y1-l)>mr)&&this._append`L${s},${l}`,n&&(f<0&&(f=f%vr+vr),f>xr?this._append`A${n},${n},0,1,${c},${t-a},${e-u}A${n},${n},0,1,${c},${this._x1=s},${this._y1=l}`:f>mr&&this._append`A${n},${n},0,${+(f>=yr)},${c},${this._x1=t+n*Math.cos(i)},${this._y1=e+n*Math.sin(i)}`)}rect(t,e,n,r){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+e}h${n=+n}v${+r}h${-n}Z`}toString(){return this._}}function _r(t,e){if((n=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var n,r=t.slice(0,n);return[r.length>1?r[0]+r.slice(2):r,+t.slice(n+1)]}function Mr(t){return(t=_r(Math.abs(t)))?t[1]:NaN}var Sr,Ar=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Tr(t){if(!(e=Ar.exec(t)))throw new Error("invalid format: "+t);var e;return new Cr({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function Cr(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function kr(t,e){var n=_r(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Tr.prototype=Cr.prototype,Cr.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var Nr={"%":(t,e)=>(100*t).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>kr(100*t,e),r:kr,s:function(t,e){var n=_r(t,e);if(!n)return t+"";var r=n[0],i=n[1],o=i-(Sr=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+_r(t,Math.max(0,e+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function jr(t){return t}var Dr,Fr,$r,Er=Array.prototype.map,Ur=["y","z","a","f","p","n","Β΅","m","","k","M","G","T","P","E","Z","Y"];function Rr(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?jr:(e=Er.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=e[0],s=0;i>0&&u>0&&(s+u+1>r&&(u=Math.max(1,r-s)),o.push(t.substring(i-=u,i+u)),!((s+=u+1)>r));)u=e[a=(a+1)%e.length];return o.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?jr:function(t){return function(e){return e.replace(/[0-9]/g,function(e){return t[+e]})}}(Er.call(t.numerals,String)),s=void 0===t.percent?"%":t.percent+"",l=void 0===t.minus?"βˆ’":t.minus+"",c=void 0===t.nan?"NaN":t.nan+"";function f(t){var e=(t=Tr(t)).fill,n=t.align,f=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,m=t.type;"n"===m?(g=!0,m="g"):Nr[m]||(void 0===y&&(y=12),v=!0,m="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var x="$"===h?i:"#"===h&&/[boxX]/.test(m)?"0"+m.toLowerCase():"",w="$"===h?o:/[%p]/.test(m)?s:"",b=Nr[m],_=/[defgprs%]/.test(m);function M(t){var i,o,s,h=x,M=w;if("c"===m)M=b(t)+M,t="";else{var S=(t=+t)<0||1/t<0;if(t=isNaN(t)?c:b(Math.abs(t),y),v&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),S&&0===+t&&"+"!==f&&(S=!1),h=(S?"("===f?f:l:"-"===f||"("===f?"":f)+h,M=("s"===m?Ur[8+Sr/3]:"")+M+(S&&"("===f?")":""),_)for(i=-1,o=t.length;++i(s=t.charCodeAt(i))||s>57){M=(46===s?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,T=A>1)+h+t+M+T.slice(A);break;default:t=T+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(m)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:f,formatPrefix:function(t,e){var n=f(((t=Tr(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Mr(e)/3))),i=Math.pow(10,-r),o=Ur[8+r/3];return function(t){return n(i*t)+o}}}}function zr(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t)}return this}function Ir(t){return+t}Dr=Rr({thousands:",",grouping:[3],currency:["$",""]}),Fr=Dr.format,$r=Dr.formatPrefix;var Or=[0,1];function Pr(t){return t}function Lr(t,e){return(e-=t=+t)?function(n){return(n-t)/e}:function(t){return function(){return t}}(isNaN(e)?NaN:.5)}function Yr(t,e,n){var r=t[0],i=t[1],o=e[0],a=e[1];return ie&&(n=t,t=e,e=n),function(n){return Math.max(t,Math.min(e,n))}}(a[0],a[t-1])),r=t>2?Vr:Yr,i=o=null,f}function f(e){return null==e||isNaN(e=+e)?n:(i||(i=r(a.map(t),u,s)))(t(l(e)))}return f.invert=function(n){return l(e((o||(o=r(u,a.map(t),sn)))(n)))},f.domain=function(t){return arguments.length?(a=Array.from(t,Ir),c()):a.slice()},f.range=function(t){return arguments.length?(u=Array.from(t),c()):u.slice()},f.rangeRound=function(t){return u=Array.from(t),s=pn,c()},f.clamp=function(t){return arguments.length?(l=!!t||Pr,c()):l!==Pr},f.interpolate=function(t){return arguments.length?(s=t,c()):s},f.unknown=function(t){return arguments.length?(n=t,f):n},function(n,r){return t=n,e=r,c()}}function qr(){return Xr()(Pr,Pr)}function Br(t,e,n,r){var i,o=B(t,e,n);switch((r=Tr(null==r?",f":r)).type){case"s":var a=Math.max(Math.abs(t),Math.abs(e));return null!=r.precision||isNaN(i=function(t,e){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Mr(e)/3)))-Mr(Math.abs(t)))}(o,a))||(r.precision=i),$r(r,a);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=function(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,Mr(e)-Mr(t))+1}(o,Math.max(Math.abs(t),Math.abs(e))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=function(t){return Math.max(0,-Mr(Math.abs(t)))}(o))||(r.precision=i-2*("%"===r.type))}return Fr(r)}function Wr(t){var e=t.domain;return t.ticks=function(t){var n=e();return function(t,e,n){if(!((n=+n)>0))return[];if((t=+t)===(e=+e))return[t];const r=e=i))return[];const u=o-i+1,s=new Array(u);if(r)if(a<0)for(let t=0;t0;){if((i=q(s,l,n))===r)return o[a]=s,o[u]=l,e(o);if(i>0)s=Math.floor(s/i)*i,l=Math.ceil(l/i)*i;else{if(!(i<0))break;s=Math.ceil(s*i)/i,l=Math.floor(l*i)/i}r=i}return t},t}function Jr(){var t=qr();return t.copy=function(){return Hr(t,Jr())},zr.apply(t,arguments),Wr(t)}const Gr=new Date,Zr=new Date;function Qr(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=e=>(t(e=new Date(+e)),e),i.ceil=n=>(t(n=new Date(n-1)),e(n,1),t(n),n),i.round=t=>{const e=i(t),n=i.ceil(t);return t-e(e(t=new Date(+t),null==n?1:Math.floor(n)),t),i.range=(n,r,o)=>{const a=[];if(n=i.ceil(n),o=null==o?1:Math.floor(o),!(n0))return a;let u;do{a.push(u=new Date(+n)),e(n,o),t(n)}while(uQr(e=>{if(e>=e)for(;t(e),!n(e);)e.setTime(e-1)},(t,r)=>{if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}),n&&(i.count=(e,r)=>(Gr.setTime(+e),Zr.setTime(+r),t(Gr),t(Zr),Math.floor(n(Gr,Zr))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?e=>r(e)%t===0:e=>i.count(0,e)%t===0):i:null)),i}const Kr=Qr(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);Kr.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?Qr(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):Kr:null),Kr.range;const ti=1e3,ei=6e4,ni=36e5,ri=864e5,ii=6048e5,oi=2592e6,ai=31536e6,ui=Qr(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*ti)},(t,e)=>(e-t)/ti,t=>t.getUTCSeconds());ui.range;const si=Qr(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*ti)},(t,e)=>{t.setTime(+t+e*ei)},(t,e)=>(e-t)/ei,t=>t.getMinutes());si.range;const li=Qr(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*ei)},(t,e)=>(e-t)/ei,t=>t.getUTCMinutes());li.range;const ci=Qr(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*ti-t.getMinutes()*ei)},(t,e)=>{t.setTime(+t+e*ni)},(t,e)=>(e-t)/ni,t=>t.getHours());ci.range;const fi=Qr(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*ni)},(t,e)=>(e-t)/ni,t=>t.getUTCHours());fi.range;const hi=Qr(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*ei)/ri,t=>t.getDate()-1);hi.range;const di=Qr(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/ri,t=>t.getUTCDate()-1);di.range;const pi=Qr(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/ri,t=>Math.floor(t/ri));function gi(t){return Qr(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(t,e)=>{t.setDate(t.getDate()+7*e)},(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*ei)/ii)}pi.range;const yi=gi(0),vi=gi(1),mi=gi(2),xi=gi(3),wi=gi(4),bi=gi(5),_i=gi(6);function Mi(t){return Qr(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+7*e)},(t,e)=>(e-t)/ii)}yi.range,vi.range,mi.range,xi.range,wi.range,bi.range,_i.range;const Si=Mi(0),Ai=Mi(1),Ti=Mi(2),Ci=Mi(3),ki=Mi(4),Ni=Mi(5),ji=Mi(6);Si.range,Ai.range,Ti.range,Ci.range,ki.range,Ni.range,ji.range;const Di=Qr(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear()),t=>t.getMonth());Di.range;const Fi=Qr(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+12*(e.getUTCFullYear()-t.getUTCFullYear()),t=>t.getUTCMonth());Fi.range;const $i=Qr(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());$i.every=t=>isFinite(t=Math.floor(t))&&t>0?Qr(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)}):null,$i.range;const Ei=Qr(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());Ei.every=t=>isFinite(t=Math.floor(t))&&t>0?Qr(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)}):null,Ei.range;const[Ui,Ri]=function(t,e,n,r,i,o){const a=[[ui,1,ti],[ui,5,5e3],[ui,15,15e3],[ui,30,3e4],[o,1,ei],[o,5,3e5],[o,15,9e5],[o,30,18e5],[i,1,ni],[i,3,108e5],[i,6,216e5],[i,12,432e5],[r,1,ri],[r,2,1728e5],[n,1,ii],[e,1,oi],[e,3,7776e6],[t,1,ai]];function u(e,n,r){const i=Math.abs(n-e)/r,o=O(([,,t])=>t).right(a,i);if(o===a.length)return t.every(B(e/ai,n/ai,r));if(0===o)return Kr.every(Math.max(B(e,n,r),1));const[u,s]=a[i/a[o-1][2][t.toLowerCase(),e]))}function Gi(t,e,n){var r=Vi.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function Zi(t,e,n){var r=Vi.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function Qi(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function Ki(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function to(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function eo(t,e,n){var r=Vi.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function no(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function ro(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function io(t,e,n){var r=Vi.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function oo(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function ao(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function uo(t,e,n){var r=Vi.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function so(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function lo(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function co(t,e,n){var r=Vi.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function fo(t,e,n){var r=Vi.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function ho(t,e,n){var r=Vi.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function po(t,e,n){var r=Hi.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function go(t,e,n){var r=Vi.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function yo(t,e,n){var r=Vi.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function vo(t,e){return qi(t.getDate(),e,2)}function mo(t,e){return qi(t.getHours(),e,2)}function xo(t,e){return qi(t.getHours()%12||12,e,2)}function wo(t,e){return qi(1+hi.count($i(t),t),e,3)}function bo(t,e){return qi(t.getMilliseconds(),e,3)}function _o(t,e){return bo(t,e)+"000"}function Mo(t,e){return qi(t.getMonth()+1,e,2)}function So(t,e){return qi(t.getMinutes(),e,2)}function Ao(t,e){return qi(t.getSeconds(),e,2)}function To(t){var e=t.getDay();return 0===e?7:e}function Co(t,e){return qi(yi.count($i(t)-1,t),e,2)}function ko(t){var e=t.getDay();return e>=4||0===e?wi(t):wi.ceil(t)}function No(t,e){return t=ko(t),qi(wi.count($i(t),t)+(4===$i(t).getDay()),e,2)}function jo(t){return t.getDay()}function Do(t,e){return qi(vi.count($i(t)-1,t),e,2)}function Fo(t,e){return qi(t.getFullYear()%100,e,2)}function $o(t,e){return qi((t=ko(t)).getFullYear()%100,e,2)}function Eo(t,e){return qi(t.getFullYear()%1e4,e,4)}function Uo(t,e){var n=t.getDay();return qi((t=n>=4||0===n?wi(t):wi.ceil(t)).getFullYear()%1e4,e,4)}function Ro(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+qi(e/60|0,"0",2)+qi(e%60,"0",2)}function zo(t,e){return qi(t.getUTCDate(),e,2)}function Io(t,e){return qi(t.getUTCHours(),e,2)}function Oo(t,e){return qi(t.getUTCHours()%12||12,e,2)}function Po(t,e){return qi(1+di.count(Ei(t),t),e,3)}function Lo(t,e){return qi(t.getUTCMilliseconds(),e,3)}function Yo(t,e){return Lo(t,e)+"000"}function Vo(t,e){return qi(t.getUTCMonth()+1,e,2)}function Ho(t,e){return qi(t.getUTCMinutes(),e,2)}function Xo(t,e){return qi(t.getUTCSeconds(),e,2)}function qo(t){var e=t.getUTCDay();return 0===e?7:e}function Bo(t,e){return qi(Si.count(Ei(t)-1,t),e,2)}function Wo(t){var e=t.getUTCDay();return e>=4||0===e?ki(t):ki.ceil(t)}function Jo(t,e){return t=Wo(t),qi(ki.count(Ei(t),t)+(4===Ei(t).getUTCDay()),e,2)}function Go(t){return t.getUTCDay()}function Zo(t,e){return qi(Ai.count(Ei(t)-1,t),e,2)}function Qo(t,e){return qi(t.getUTCFullYear()%100,e,2)}function Ko(t,e){return qi((t=Wo(t)).getUTCFullYear()%100,e,2)}function ta(t,e){return qi(t.getUTCFullYear()%1e4,e,4)}function ea(t,e){var n=t.getUTCDay();return qi((t=n>=4||0===n?ki(t):ki.ceil(t)).getUTCFullYear()%1e4,e,4)}function na(){return"+0000"}function ra(){return"%"}function ia(t){return+t}function oa(t){return Math.floor(+t/1e3)}function aa(t){return new Date(t)}function ua(t){return t instanceof Date?+t:+new Date(+t)}function sa(t,e,n,r,i,o,a,u,s,l){var c=qr(),f=c.invert,h=c.domain,d=l(".%L"),p=l(":%S"),g=l("%I:%M"),y=l("%I %p"),v=l("%a %d"),m=l("%b %d"),x=l("%B"),w=l("%Y");function b(t){return(s(t)=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:ia,s:oa,S:Ao,u:To,U:Co,V:No,w:jo,W:Do,x:null,X:null,y:Fo,Y:Eo,Z:Ro,"%":ra},w={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return s[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:zo,e:zo,f:Yo,g:Ko,G:ea,H:Io,I:Oo,j:Po,L:Lo,m:Vo,M:Ho,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:ia,s:oa,S:Xo,u:qo,U:Bo,V:Jo,w:Go,W:Zo,x:null,X:null,y:Qo,Y:ta,Z:na,"%":ra},b={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p.get(r[0].toLowerCase()),n+r[0].length):-1},A:function(t,e,n){var r=f.exec(e.slice(n));return r?(t.w=h.get(r[0].toLowerCase()),n+r[0].length):-1},b:function(t,e,n){var r=v.exec(e.slice(n));return r?(t.m=m.get(r[0].toLowerCase()),n+r[0].length):-1},B:function(t,e,n){var r=g.exec(e.slice(n));return r?(t.m=y.get(r[0].toLowerCase()),n+r[0].length):-1},c:function(t,n,r){return S(t,e,n,r)},d:ao,e:ao,f:ho,g:no,G:eo,H:so,I:so,j:uo,L:fo,m:oo,M:lo,p:function(t,e,n){var r=l.exec(e.slice(n));return r?(t.p=c.get(r[0].toLowerCase()),n+r[0].length):-1},q:io,Q:go,s:yo,S:co,u:Zi,U:Qi,V:Ki,w:Gi,W:to,x:function(t,e,r){return S(t,n,e,r)},X:function(t,e,n){return S(t,r,e,n)},y:no,Y:eo,Z:ro,"%":po};function _(t,e){return function(n){var r,i,o,a=[],u=-1,s=0,l=t.length;for(n instanceof Date||(n=new Date(+n));++u53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=Ii(Oi(o.y,0,1))).getUTCDay(),r=i>4||0===i?Ai.ceil(r):Ai(r),r=di.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=zi(Oi(o.y,0,1))).getDay(),r=i>4||0===i?vi.ceil(r):vi(r),r=hi.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?Ii(Oi(o.y,0,1)).getUTCDay():zi(Oi(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,Ii(o)):zi(o)}}function S(t,e,n,r){for(var i,o,a=0,u=e.length,s=n.length;a=s)return-1;if(37===(i=e.charCodeAt(a++))){if(i=e.charAt(a++),!(o=b[i in Yi?e.charAt(a++):i])||(r=o(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return x.x=_(n,x),x.X=_(r,x),x.c=_(e,x),w.x=_(n,w),w.X=_(r,w),w.c=_(e,w),{format:function(t){var e=_(t+="",x);return e.toString=function(){return t},e},parse:function(t){var e=M(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=_(t+="",w);return e.toString=function(){return t},e},utcParse:function(t){var e=M(t+="",!0);return e.toString=function(){return t},e}}}(t),Li=Pi.format,Pi.parse,Pi.utcFormat,Pi.utcParse}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});const fa=Math.abs,ha=Math.atan2,da=Math.cos,pa=Math.max,ga=Math.min,ya=Math.sin,va=Math.sqrt,ma=1e-12,xa=Math.PI,wa=xa/2,ba=2*xa;function _a(t){return t>=1?wa:t<=-1?-wa:Math.asin(t)}function Ma(t){let e=3;return t.digits=function(n){if(!arguments.length)return e;if(null==n)e=null;else{const t=Math.floor(n);if(!(t>=0))throw new RangeError(`invalid digits: ${n}`);e=t}return t},()=>new br(e)}function Sa(t){return t.innerRadius}function Aa(t){return t.outerRadius}function Ta(t){return t.startAngle}function Ca(t){return t.endAngle}function ka(t){return t&&t.padAngle}function Na(t,e,n,r,i,o,a){var u=t-n,s=e-r,l=(a?o:-o)/va(u*u+s*s),c=l*s,f=-l*u,h=t+c,d=e+f,p=n+c,g=r+f,y=(h+p)/2,v=(d+g)/2,m=p-h,x=g-d,w=m*m+x*x,b=i-o,_=h*g-p*d,M=(x<0?-1:1)*va(pa(0,b*b*w-_*_)),S=(_*x-m*M)/w,A=(-_*m-x*M)/w,T=(_*x+m*M)/w,C=(-_*m+x*M)/w,k=S-y,N=A-v,j=T-y,D=C-v;return k*k+N*N>j*j+D*D&&(S=T,A=C),{cx:S,cy:A,x01:-c,y01:-f,x11:S*(i/b-1),y11:A*(i/b-1)}}function ja(){var t=Sa,e=Aa,n=ca(0),r=null,i=Ta,o=Ca,a=ka,u=null,s=Ma(l);function l(){var l,c,f=+t.apply(this,arguments),h=+e.apply(this,arguments),d=i.apply(this,arguments)-wa,p=o.apply(this,arguments)-wa,g=fa(p-d),y=p>d;if(u||(u=l=s()),hma)if(g>ba-ma)u.moveTo(h*da(d),h*ya(d)),u.arc(0,0,h,d,p,!y),f>ma&&(u.moveTo(f*da(p),f*ya(p)),u.arc(0,0,f,p,d,y));else{var v,m,x=d,w=p,b=d,_=p,M=g,S=g,A=a.apply(this,arguments)/2,T=A>ma&&(r?+r.apply(this,arguments):va(f*f+h*h)),C=ga(fa(h-f)/2,+n.apply(this,arguments)),k=C,N=C;if(T>ma){var j=_a(T/f*ya(A)),D=_a(T/h*ya(A));(M-=2*j)>ma?(b+=j*=y?1:-1,_-=j):(M=0,b=_=(d+p)/2),(S-=2*D)>ma?(x+=D*=y?1:-1,w-=D):(S=0,x=w=(d+p)/2)}var F=h*da(x),$=h*ya(x),E=f*da(_),U=f*ya(_);if(C>ma){var R,z=h*da(w),I=h*ya(w),O=f*da(b),P=f*ya(b);if(g1?0:t<-1?xa:Math.acos(t)}((L*V+Y*H)/(va(L*L+Y*Y)*va(V*V+H*H)))/2),q=va(R[0]*R[0]+R[1]*R[1]);k=ga(C,(f-q)/(X-1)),N=ga(C,(h-q)/(X+1))}else k=N=0}S>ma?N>ma?(v=Na(O,P,F,$,h,N,y),m=Na(z,I,E,U,h,N,y),u.moveTo(v.cx+v.x01,v.cy+v.y01),Nma&&M>ma?k>ma?(v=Na(E,U,z,I,f,-k,y),m=Na(F,$,O,P,f,-k,y),u.lineTo(v.cx+v.x01,v.cy+v.y01),k=f;--h)u.point(v[h],m[h]);u.lineEnd(),u.areaEnd()}y&&(v[c]=+t(d,c,l),m[c]=+e(d,c,l),u.point(r?+r(d,c,l):v[c],n?+n(d,c,l):m[c]))}if(p)return u=null,p+""||null}function c(){return Ra().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?Ea:ca(+t),e="function"==typeof e?e:ca(void 0===e?0:+e),n="function"==typeof n?n:void 0===n?Ua:ca(+n),l.x=function(e){return arguments.length?(t="function"==typeof e?e:ca(+e),r=null,l):t},l.x0=function(e){return arguments.length?(t="function"==typeof e?e:ca(+e),l):t},l.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:ca(+t),l):r},l.y=function(t){return arguments.length?(e="function"==typeof t?t:ca(+t),n=null,l):e},l.y0=function(t){return arguments.length?(e="function"==typeof t?t:ca(+t),l):e},l.y1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:ca(+t),l):n},l.lineX0=l.lineY0=function(){return c().x(t).y(e)},l.lineY1=function(){return c().x(t).y(n)},l.lineX1=function(){return c().x(r).y(e)},l.defined=function(t){return arguments.length?(i="function"==typeof t?t:ca(!!t),l):i},l.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),l):a},l.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),l):o},l}Fa.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._context.lineTo(t,e)}}};var Ia=Pa($a);function Oa(t){this._curve=t}function Pa(t){function e(e){return new Oa(t(e))}return e._curve=t,e}function La(){return t=Ra().curve(Ia),e=t.curve,t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?e(Pa(t)):e()._curve},t;var t,e}Oa.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,e){this._curve.point(e*Math.sin(t),e*-Math.cos(t))}};var Ya={draw(t,e){const n=va(e/xa);t.moveTo(n,0),t.arc(0,0,n,0,ba)}};const Va=va(3);var Ha={draw(t,e){const n=-va(e/(3*Va));t.moveTo(0,2*n),t.lineTo(-Va*n,-n),t.lineTo(Va*n,-n),t.closePath()}};function Xa(t,e){let n=null,r=Ma(i);function i(){let i;if(n||(n=i=r()),t.apply(this,arguments).draw(n,+e.apply(this,arguments)),i)return n=null,i+""||null}return t="function"==typeof t?t:ca(t||Ya),e="function"==typeof e?e:ca(void 0===e?64:+e),i.type=function(e){return arguments.length?(t="function"==typeof e?e:ca(e),i):t},i.size=function(t){return arguments.length?(e="function"==typeof t?t:ca(+t),i):e},i.context=function(t){return arguments.length?(n=null==t?null:t,i):n},i}function qa(t){return t<0?-1:1}function Ba(t,e,n){var r=t._x1-t._x0,i=e-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(n-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(qa(o)+qa(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function Wa(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function Ja(t,e,n){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*e,o-u,a-u*n,o,a)}function Ga(t){this._context=t}function Za(t){return new Ga(t)}function Qa(t,e,n){this.k=t,this.x=e,this.y=n}Ga.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:Ja(this,this._t0,Wa(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){var n=NaN;if(e=+e,(t=+t)!==this._x1||e!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,Ja(this,Wa(this,n=Ba(this,t,e)),n);break;default:Ja(this,this._t0,n=Ba(this,t,e))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e,this._t0=n}}},Object.create(Ga.prototype).point=function(t,e){Ga.prototype.point.call(this,e,t)},Qa.prototype={constructor:Qa,scale:function(t){return 1===t?this:new Qa(this.k*t,this.x,this.y)},translate:function(t,e){return 0===t&0===e?this:new Qa(this.k,this.x+this.k*t,this.y+this.k*e)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}},Qa.prototype;function Ka(t,e){return e.replace("YYYY",String(t.getFullYear())).replace("MM",String(t.getMonth()+1).padStart(2,"0")).replace("DD",String(t.getDate()).padStart(2,"0")).replace("HH",String(t.getHours()).padStart(2,"0")).replace("hh",String(t.getHours()%12||12).padStart(2,"0")).replace("mm",String(t.getMinutes()).padStart(2,"0")).replace("ss",String(t.getSeconds()).padStart(2,"0"))}!function(t,e){void 0===e&&(e={});var n=e.insertAt;if("undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===n&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=t:i.appendChild(document.createTextNode(t))}}(".pointer-wrapper {\n position: relative;\n}\n\n.pointer-wrapper:hover::after {\n content: attr(data-tooltip);\n position: absolute;\n left: 50%;\n top: -10px;\n transform: translate(-50%, -100%);\n background: black;\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n border-radius: 4px;\n white-space: nowrap;\n pointer-events: none;\n}\n#gauge-tooltip {\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 6px 10px;\n border-radius: 6px;\n font-size: 13px;\n transition: opacity 0.2s ease, transform 0.2s ease;\n transform: translateY(-5px);\n white-space: nowrap;\n}\n\n.spinner {\n border: 4px solid rgba(0, 0, 0, 0.1);\n border-top-color: rgba(0, 0, 0, 0.7);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}");var tu=function(t){return t?Array.isArray(t)?Object.assign.apply(Object,c([{}],t,!1)):"function"==typeof t?t({}):t:{}},eu=function(t){return t<1e12?new Date(1e3*t):new Date(t)},nu="Roboto, sans-serif",ru={container:{width:400,height:250,padding:2,margin:0,display:"flex",flexDirection:"column",justifyContent:"flex-start",alignItems:"center",borderRadius:10,boxSizing:"border-box",gap:0,background:"rgb(248, 249, 250)",border:"1px solid rgba(211, 216, 220, 1)",textAlign:"center",fontFamily:nu},title:{fontWeight:600,color:"rgba(0,0,0,0.75)",fontFamily:nu},tooltip:{background:"rgba(0,0,0,0.75)",color:"#ffffff",borderRadius:"6px",padding:"6px 10px",fontSize:"12px"},axis:{color:"#666",fontSize:"11px",fontFamily:nu},chart:{strokeColor:"#1e88e5",strokeWidth:2,gradientColors:["#1e88e5","#90caf9"],dotRadius:4}},iu=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return o(n,e),n.prototype.render=function(){var e=this.props,n=e.children,r=u(e,["children"]);return t.jsx("svg",a({},r,{children:n}))},n}(e.PureComponent),ou=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return o(n,e),n.prototype.render=function(){var e=this.props,n=e.width,r=void 0===n?12.5:n,i=e.head,o=void 0===i?95:i,a=e.tail,u=void 0===a?5:a,s=e.value,l=void 0===s?-5:s,c=e.tooltip,f=void 0===c?"":c,h=e.center,d=void 0===h?{x:125,y:135}:h,p=e.minAngle,g=e.maxAngle,y=e.disabled,v=Ra()([[r/2,0],[0,-o],[-r/2,0],[0,u],[r/2,0]]),m=Jr().domain([0,1]).range([p,g])(l),x=function(t){var e=document.getElementById("gauge-tooltip");e&&(e.style.left=t.clientX+10+"px",e.style.top=t.clientY-20+"px")};return t.jsx("g",{className:"pointer-wrapper","data-tooltip":f,children:t.jsx("path",{className:"gauge-pointer",d:null!=v?v:void 0,transform:"translate(".concat(d.x,", ").concat(d.y,") rotate(").concat(m,")"),fill:"#333",opacity:y?.3:void 0,style:{transition:"all 0.25s 0.25s",color:"white"},onMouseEnter:function(t){return function(t,e){var n=document.getElementById("gauge-tooltip");n&&e&&(n.textContent=e,n.style.opacity="1",n.style.transform="translateY(0px)",x(t))}(t,f)},onMouseMove:function(t){return x(t)},onMouseLeave:function(){var t=document.getElementById("gauge-tooltip");t&&(t.style.opacity="0",t.style.transform="translateY(-5px)")},children:f&&t.jsx("title",{children:f})})})},n}(e.PureComponent),au=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return o(n,e),n.prototype.render=function(){var e,n=this.props,r=n.center,i=n.disabled;return t.jsx("path",{className:"gauge-target",d:null!==(e=Xa().type(Ha)())&&void 0!==e?e:void 0,transform:"translate(".concat(r.x,",").concat(r.y-110,") rotate(180)"),fill:i?"#adb2ba":"#ffa500",stroke:i?"#adb2ba":"#000",strokeWidth:1,style:{transition:"all 0.25s 0.25s"}})},n}(e.PureComponent),uu=function(e,n){switch(n){case"superscript":return t.jsx("sup",{children:e});case"subscript":return t.jsx("sub",{children:e});default:return t.jsx("span",{children:e})}},su=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return o(n,e),n.prototype.render=function(){var e=this.props;e.value;var n=e.disabled,r=e.center,i=e.offsetText;e.uom;var o=e.mergedValueSx,s=e.mergedUnitSx,l=e.formatted;return u(e,["value","disabled","center","offsetText","uom","mergedValueSx","mergedUnitSx","formatted"]),t.jsx("foreignObject",{x:r.x-100+i,y:r.y-40,width:200,height:80,pointerEvents:"none",opacity:n?.4:void 0,children:t.jsxs("div",{style:a(a({display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",gap:4},o),{background:"transparent"}),children:[l.unitText&&"left"===l.position&&t.jsx("div",{style:s,children:uu(l.unitText,l.unitStyle)}),t.jsx("div",{style:o,children:l.text}),l.unitText&&"right"===l.position&&t.jsx("div",{style:s,children:uu(l.unitText,l.unitStyle)}),l.unitText&&"top"===l.position&&t.jsx("div",{style:a(a({},s),{order:-1}),children:uu(l.unitText,l.unitStyle)}),l.unitText&&"bottom"===l.position&&t.jsx("div",{style:a(a({},s),{order:1}),children:uu(l.unitText,l.unitStyle)})]})})},n}(e.PureComponent),lu=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return o(n,e),n.prototype.render=function(){var e=this.props,n=e.inset,r=void 0===n?0:n,i=e.min,o=void 0===i?0:i,s=e.max,l=void 0===s?1:s,c=e.maxAngle,f=e.minAngle,h=e.center,d=void 0===h?{x:125,y:135}:h,p=u(e,["inset","min","max","maxAngle","minAngle","center"]),g=c/180,y=Math.PI*g,v=f/180,m=Math.PI*v,x=Jr().domain([0,1]).range([m,y]),w=Jr().domain([0,39]).range([x(o),x(l)]),b=La().angle(function(t,e){return w(e)}).radius(100-r)({length:40});return t.jsx("path",a({className:"guage-arc",d:b,transform:"translate(".concat(d.x,",").concat(d.y,")"),fill:"transparent",style:{transition:"all 0.25s 0.25s"}},p))},n}(e.PureComponent),cu=Ra().x(0).y(function(t,e){return e})(Array.from({length:35})),fu=Ra().x(0).y(function(t,e){return e})(Array.from({length:12})),hu=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return o(n,e),n.prototype.render=function(){var e=this.props,n=e.disabled,r=e.center,i=e.tickCount,o=e.min,a=e.max,u=e.maxAngle,s=e.minAngle,l=e.offsetText,f=e.length,h=void 0===f?120:f,d=function(t,e,n,r,i){t%2==0&&console.warn("Ticks should be odd numbered to ensure a tick in in the middle of the gauge.");var o=Jr().domain([0,t-1]).range([0,1]),a=Jr().domain([0,t-1]).range([e,n]),u=Jr().domain([0,1]).range([r,i]);return c([],Array(t),!0).map(function(t,e){return{index:e,val:a(e),deg:u(o(e))}})}(i,o,a,s,u);return d.map(function(e){var i,o=e.val,a=e.deg,u=e.index;return t.jsxs("g",{className:"gauge-label",style:{userSelect:"none",textAlign:"center"},transform:"translate(".concat(r.x,",").concat(r.y,") rotate(").concat(a,")"),children:[t.jsx("path",{d:null!==(i=0===u||u===d.length-1?cu:fu)&&void 0!==i?i:void 0,stroke:"#344c69",strokeWidth:"1",transform:"translate(0,".concat(7.5-h,")"),style:{transition:"all .25s .25s"},opacity:n?.4:void 0}),t.jsx("text",{transform:"translate(".concat(l,",").concat(-h,")"),style:{transition:"all .25s .25s",fontSize:"85%"},opacity:n?.4:void 0,children:Number(o)})]},o)})},n}(e.PureComponent);!function(e){function n(){return null!==e&&e.apply(this,arguments)||this}o(n,e),n.prototype.render=function(){var e=this.props,n=e.start,r=e.end,i=e.id,o=e.disabled;return t.jsx("defs",{children:t.jsxs("linearGradient",{id:i,x1:"0%",y1:"0%",x2:"0%",y2:"100%",children:[t.jsx("stop",{offset:"0%",stopColor:o?"rgba(0,0,0,0)":n}),t.jsx("stop",{offset:"100%",stopColor:o?"rgba(0,0,0,0.4)":r})]})})}}(e.PureComponent);var du=function(n){var r=n.height,i=void 0===r?400:r,o=n.width,s=void 0===o?400:o,l=n.disabled,c=void 0!==l&&l,f=n.value,h=void 0===f?-1:f,d=n.min,p=void 0===d?0:d,g=n.max,y=void 0===g?100:g,v=n.maxAngle,m=void 0===v?135:v,x=n.minAngle,w=void 0===x?-135:x,b=n.tickCount,_=void 0===b?5:b,M=n.arcSegments,S=void 0===M?[{min:0,max:1,color:"skyblue"}]:M,A=n.labelProps,T=void 0===A?{offsetText:-7.5}:A,C=n.uom,k=void 0===C?"":C,N=n.uomProps,j=void 0===N?{offsetText:-10}:N,D=n.pointerLabel,F=void 0===D?"":D,$=n.mergedUnitSx,E=void 0===$?{}:$,U=n.mergedValueSx,R=void 0===U?{}:U,z=n.formatted,I=u(n,["height","width","disabled","value","min","max","maxAngle","minAngle","tickCount","arcSegments","labelProps","uom","uomProps","pointerLabel","mergedUnitSx","mergedValueSx","formatted"]),O={x:140,y:140},P=e.useCallback(Jr().domain([p,y]).range([0,1]),[p,y]),L=e.useMemo(function(){return P(h)},[h,P]);return t.jsx(t.Fragment,{children:t.jsxs(iu,a({className:"gauge",width:s||(i||250),height:i||(s||250),viewBox:"0 0 280 280",style:{transition:"all 0.25s 0.25s"}},I,{children:[t.jsx(lu,{stroke:"#344c69",strokeWidth:4,center:O,maxAngle:m,minAngle:w,opacity:c?.25:void 0}),t.jsx(hu,a({disabled:c,center:O,tickCount:_,min:p,max:y,maxAngle:m,minAngle:w},T)),S.map(function(e,n){var r=e.min,i=e.max,o=e.color;return t.jsx("g",{children:t.jsx(lu,{inset:12,min:r,max:i,stroke:o,strokeWidth:20,center:O,maxAngle:m,minAngle:w},"gauge-arcsegment-".concat(n))},"arcsegment-".concat(n))}),t.jsx(au,{center:O,disabled:c}),t.jsx(ou,{value:c?-.025:L,center:O,disabled:c,maxAngle:m,minAngle:w,tooltip:F||h}),t.jsx(su,a({value:h,uom:k,disabled:c,center:O,mergedValueSx:R,mergedUnitSx:E,formatted:z},j))]}))})},pu=function(t){return t?Array.isArray(t)?Object.assign.apply(Object,c([{}],t,!1)):"function"==typeof t?t({}):t:{}},gu="Roboto, sans-serif",yu={trackColor:"#e6e6e6",progressColor:"#4caf50",progressStroke:"none",fontSize:"20px",fontFamily:gu},vu={fontSize:"12px",color:"#666",fontFamily:gu},mu=[{from:0,to:40,color:"#4caf50"},{from:40,to:60,color:"#ffeb3b"},{from:60,to:100,color:"#f44336"}],xu={width:400,height:250,padding:2,margin:0,display:"flex",flexDirection:"column",justifyContent:"flex-start",alignItems:"center",borderRadius:10,boxSizing:"border-box",background:"rgb(248, 249, 250)",border:"1px solid rgba(211, 216, 220, 1)",fontFamily:gu,color:"#000000",overflowWrap:"break-word",label:{fontWeight:500,color:"#000000",fontFamily:gu},value:{fontWeight:700,color:"#000000",fontFamily:gu},unit:{fontWeight:400,color:"#000000",fontFamily:gu}};exports.ChartWidget=function(n){var r,i,o,u,c,f,h,d,p,g,y,v,m=n.client,x=n.nodeId,w=n.variable,b=n.from,_=n.to,M=n.limit,S=void 0===M?20:M,A=n.title,T=void 0===A?"Latest Data":A,C=n.styles,k=void 0===C?{}:C,N=n.tooltipFormatter,D=void 0===N?function(t){return"".concat(new Date(new Date(t.timestamp<1e12?1e3*t.timestamp:t.timestamp)).toLocaleString(void 0,{month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!0}),": ").concat(t.value)}:N,F=n.tickCount,$=void 0===F?4:F,E=n.tickFormatter,U=n.xTickFormat,R=n.yTickFormat,z=n.tooltipFormat,I=n.onStyleChange;j("Chart Widget",{client:m,nodeId:x,variable:w,from:b,to:_},["client","nodeId","variable","from time","to time"]);var O="string"==typeof U?function(t){return Ka(t,U)}:U,P="string"==typeof R?function(t){return function(t,e){if(/0\.0+/.test(e)){var n=e.split(".")[1].length;return t.toFixed(n)}return e.includes("value")&&e.includes("unit")?e.replace("value",String(t)).replace("unit",""):String(t)}(t,R)}:R,L="string"==typeof z?function(t){return"".concat(Ka(eu(t.timestamp),z),": ").concat(t.value)}:z,Y=e.useRef(null),V=e.useRef(null),H=e.useState([]),X=H[0],q=H[1],B=e.useState(!1),W=B[0],J=B[1],G=e.useState(null),Z=G[0],Q=G[1],K=e.useState(null),tt=K[0],nt=K[1],rt={data:X,loading:W,error:Z},it=e.useState({}),ot=it[0],at=it[1],ut="function"==typeof k?k(rt):k||{},st={container:a(a({},ut.container),null==ot?void 0:ot.container),title:a(a({},ut.title),null==ot?void 0:ot.title),tooltip:a(a({},ut.tooltip),null==ot?void 0:ot.tooltip),chart:a(a({},ut.chart),null==ot?void 0:ot.chart),axis:a(a({},ut.axis),null==ot?void 0:ot.axis),fontFamily:null!==(r=null==ot?void 0:ot.fontFamily)&&void 0!==r?r:ut.fontFamily},lt=e.useRef(!1),ct=e.useRef(0),ft=e.useRef(!1),ht=tu(null==st?void 0:st.container),dt=tu(null==st?void 0:st.title),pt=tu(null==st?void 0:st.tooltip),gt=null!==(i=st.chart)&&void 0!==i?i:{},yt=tu(null==st?void 0:st.axis),vt=ru.container,mt=null!==(o=ht.width)&&void 0!==o?o:vt.width,xt=null!==(u=ht.height)&&void 0!==u?u:vt.height,wt=null!==(c=null==st?void 0:st.fontFamily)&&void 0!==c?c:"Roboto",bt=null!==(f=dt.fontFamily)&&void 0!==f?f:wt,_t=.15*Math.min(Number(mt),Number(xt)),Mt=null!==(d=null===(h=null==st?void 0:st.title)||void 0===h?void 0:h.fontSize)&&void 0!==d?d:.6*_t,St=null!==(p=gt.strokeColor)&&void 0!==p?p:ru.chart.strokeColor,At=null!==(g=gt.strokeWidth)&&void 0!==g?g:ru.chart.strokeWidth,Tt=null!==(y=gt.gradientColors)&&void 0!==y?y:ru.chart.gradientColors,Ct=null!==(v=gt.dotRadius)&&void 0!==v?v:ru.chart.dotRadius;e.useEffect(function(){var t;if(m&&x){var e=m._anedya,n=null===(t=null==e?void 0:e.NewNode)||void 0===t?void 0:t.call(e,m,x);nt(n)}},[m,x]),e.useEffect(function(){if(lt.current=!0,tt){return s(void 0,void 0,void 0,function(){var t,e,n,r;return l(this,function(i){switch(i.label){case 0:if(ft.current||ct.current>=3)return[2];ft.current=!0,i.label=1;case 1:return i.trys.push([1,3,4,5]),J(!0),Q(null),t={variable:w,from:b,to:_,limit:S,order:"asc"},[4,tt.getData(t)];case 2:return e=i.sent(),lt.current?(e.isSuccess&&e.isDataAvailable?(q(e.data),Q("")):(console.error("error fetching data:",e.error),Q(e.error.errorMessage)),ct.current=0,[3,5]):[2];case 3:return n=i.sent(),console.error("Error fetching chart data:",n),q([]),Q(null!==(r=null==n?void 0:n.message)&&void 0!==r?r:"Failed to fetch data"),ct.current+=1,[3,5];case 4:return J(!1),lt.current&&(ft.current=!1),[7];case 5:return[2]}})}),function(){lt.current=!1}}},[tt,w]),e.useEffect(function(){var t,e,n,r,i,o,a,u,s,l,c,f;if(Y.current){var h=xe(Y.current);if(h.selectAll("*").remove(),X&&0!==X.length){var d=20,p=20,g=130,y=50,v=Math.max(10,mt-y-p),m=Math.max(10,xt-d-g),x=h.append("g").attr("transform","translate(".concat(y,",").concat(d,")")),w=X.map(function(t){return eu(t.timestamp)}),b=la().domain(function(t){let e,n;for(const r of t)null!=r&&(void 0===e?r>=r&&(e=n=r):(e>r&&(e=r),n=e)&&(n=e);else{let r=-1;for(let i of t)null!=(i=e(i,++r,t))&&(n=i)&&(n=i)}return n}(X,function(t){return Number(t.value)}))&&void 0!==t?t:10),M=Jr().domain([0,_]).nice().range([m,0]),S=null!=Tt?Tt:["#1e88e5","#90caf9"],A=null!=St?St:"#1e88e5",T=null!=At?At:2,C=null!=Ct?Ct:4,k=h.append("defs").append("linearGradient").attr("id","chartGradient").attr("x1","0%").attr("y1","0%").attr("x2","0%").attr("y2","100%");k.append("stop").attr("offset","0%").attr("stop-color",S[0]).attr("stop-opacity",.5),k.append("stop").attr("offset","100%").attr("stop-color",S[1]).attr("stop-opacity",0);var N=za().x(function(t){return b(eu(t.timestamp))}).y0(m).y1(function(t){return M(t.value)}).curve(Za);x.append("path").datum(X).attr("fill","url(#chartGradient)").attr("d",N);var j=Ra().x(function(t){return b(eu(t.timestamp))}).y(function(t){return M(t.value)}).curve(Za);x.append("path").datum(X).attr("fill","none").attr("stroke",A).attr("stroke-width",T).attr("d",j);var F=function(t,e,n){var r=Math.max(2,.012*Math.min(t,e));return null!=n?n:Math.round(r)}(v,m,C),E=x.selectAll(".dot").data(X).enter().append("circle").attr("class","dot").attr("cx",function(t){return b(eu(t.timestamp))}).attr("cy",function(t){return M(t.value)}).attr("r",F).attr("fill",A).style("cursor","default"),U=V.current;U||(U=document.createElement("div"),V.current=U,document.body.appendChild(U));var R=ru.tooltip;U.style.position="absolute",U.style.pointerEvents="none",U.style.opacity="0",U.style.background=null!==(e=pt.backgroundColor)&&void 0!==e?e:R.background,U.style.color=null!==(n=pt.color)&&void 0!==n?n:R.color,U.style.borderRadius=null!==(r=pt.borderRadius)&&void 0!==r?r:R.borderRadius,U.style.padding=null!==(i=pt.padding)&&void 0!==i?i:R.padding,U.style.fontSize=null!==(o=pt.fontSize)&&void 0!==o?o:R.fontSize,U.style.transition="opacity 120ms",E.on("mouseover",function(t,e){U.style.opacity="1",U.innerHTML=L?L(e):D(e)}).on("mousemove",function(t){var e=Math.min(window.innerWidth-200,t.pageX+8),n=Math.max(8,t.pageY-36);U.style.left="".concat(e,"px"),U.style.top="".concat(n,"px")}).on("mouseout",function(){U.style.opacity="0"});var z,I=(z=b,et(3,z)).ticks($).tickFormat(function(t){return O?O(t):function(t){return new Intl.DateTimeFormat(void 0,{month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!0}).format(t)}(t)}),H=ru.axis;x.append("g").attr("transform","translate(0,".concat(m,")")).call(I).selectAll("text").attr("transform","rotate(-30)").style("text-anchor","end").style("font-size",null!==(a=yt.fontSize)&&void 0!==a?a:H.fontSize).style("fill",null!==(u=yt.color)&&void 0!==u?u:H.color).style("font-family",null!==(s=yt.fontFamily)&&void 0!==s?s:H.fontFamily),x.append("g").call(function(t){return et(4,t)}(M).ticks(5).tickFormat(function(t){return P?P(t):String(t)})).selectAll("text").style("font-size",null!==(l=yt.fontSize)&&void 0!==l?l:H.fontSize).style("fill",null!==(c=yt.color)&&void 0!==c?c:H.color).style("font-family",null!==(f=yt.fontFamily)&&void 0!==f?f:H.fontFamily);var q="clip-".concat(Math.random().toString(36).slice(2,9));return h.append("defs").append("clipPath").attr("id",q).append("rect").attr("width",mt).attr("height",xt),h.attr("clip-path","url(#".concat(q,")")),function(){if(V.current){try{V.current.remove()}catch(t){}V.current=null}h.selectAll("*").remove()}}}},[X,mt,xt,St,At,Tt,Ct,$,E,D,yt,pt]),e.useEffect(function(){if("function"==typeof I){var t=I(X);t&&"object"==typeof t&&at(t)}},[X]);var kt=a(a({},ru.container),ht),Nt=a(a(a(a({},ru.title),{fontSize:Mt}),dt),{fontFamily:bt});return t.jsxs("div",{style:a({},kt),children:[T&&t.jsx("h2",{style:a({},Nt),children:T}),W?t.jsx("div",{style:{display:"flex",width:"100%",height:"100%",justifyContent:"center",alignItems:"center"},children:t.jsx("div",{className:"spinner",style:{width:.3*Math.min(Number(mt),Number(xt)),height:.3*Math.min(Number(mt),Number(xt))}})}):Z?t.jsx("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:t.jsx("div",{style:{background:"rgba(255, 0, 0, 0.15)",border:"1px solid rgba(255, 0, 0, 0.6)",boxShadow:"rgba(149, 157, 165, 0.2) 0px 8px 24px",color:"rgba(255, 0, 0, 0.6)",textAlign:"center",borderRadius:"5px",padding:"5px"},children:Z})}):0===(null==X?void 0:X.length)?t.jsx("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:t.jsx("div",{style:{color:"#757575",textAlign:"center",borderRadius:"5px",padding:"5px"},children:"No data available"})}):t.jsx("svg",{ref:Y,width:mt,height:"90%"})]})},exports.LatestDataGauge=function(n){var r,i,o,u,c,f,h,d,p,g,y,v,m,x,w,b,_=n.client,M=n.nodeId,S=n.variable,A=n.title,T=void 0===A?"Latest Data":A,C=n.min,k=void 0===C?0:C,N=n.max,D=void 0===N?100:N,F=n.startAngleDeg,$=void 0===F?-135:F,E=n.endAngleDeg,U=void 0===E?135:E,R=n.thickness,z=n.zones,I=void 0===z?mu:z,O=n.showNeedle,P=void 0!==O&&O,L=n.needleColor,Y=void 0===L?"#111":L,V=n.needleWidth,H=void 0===V?3:V,X=n.subtitle,q=n.styles,B=void 0===q?{}:q,W=n.disabled,J=void 0!==W&&W,G=n.tickCount,Z=void 0===G?11:G,Q=n.unit,K=void 0===Q?"Units":Q,tt=n.uomOffset,et=void 0===tt?-15:tt,nt=n.labelOffset,rt=void 0===nt?-7:nt,it=n.onMetrics,ot=n.valueText,at=void 0===ot?function(t){var e=t.value;t.valueMin;var n=t.valueMax;return void 0===e?"-- / ".concat(n):"".concat(e," / ").concat(n)}:ot,ut=n.onStyleChange,st=n.displayText;j("LatestDataGauge",{client:_,nodeId:M,variable:S},["client","nodeId","variable"]);var lt=e.useState(null),ct=lt[0],ft=lt[1],ht=e.useState(null),dt=ht[0],pt=ht[1],gt=e.useState(!1),yt=gt[0],vt=gt[1],mt=e.useState(null),xt=mt[0],wt=mt[1],bt={value:ct,loading:yt,error:xt},_t=e.useState({}),Mt=_t[0],St=_t[1],At="function"==typeof B?B(bt):B||{},Tt={container:a(a({},At.container),null==Mt?void 0:Mt.container),label:a(a({},At.label),null==Mt?void 0:Mt.label),value:a(a({},At.value),null==Mt?void 0:Mt.value),unit:a(a({},At.unit),null==Mt?void 0:Mt.unit),fontFamily:null!==(r=null==Mt?void 0:Mt.fontFamily)&&void 0!==r?r:At.fontFamily,subtitle:a(a(a({},vu),At.subtitle),Mt.subtitle),arc:a(a(a({},yu),At.arc),Mt.arc)},Ct=e.useRef(!1),kt=e.useRef(0),Nt=e.useRef(!1),jt=e.useRef(null),Dt=pu(Tt.container),Ft=pu(Tt.label),$t=pu(Tt.value),Et=pu(Tt.subtitle),Ut=pu(Tt.unit),Rt=pu(Tt.arc),zt=xu,It=null!==(i=Dt.width)&&void 0!==i?i:zt.width,Ot=null!==(o=Dt.height)&&void 0!==o?o:zt.height,Pt=function(t){return t*Math.PI/180},Lt=e.useMemo(function(){var t,e=It/2,n=Ot/2,r=Math.min(It/2,Ot/2)-8,i=r,o=Math.max(6,i-(null!=R?R:Math.round(.2*i))),a=Pt($),u=Pt(U),s=void 0===ct?void 0:void 0===(t=ct)?void 0:Math.max(k,Math.min(D,t)),l=a+(void 0===s?0:(s-k)/(D-k))*(u-a);return{maxRadius:r,valueAngleDeg:180*l/Math.PI,valueAngleRad:l,startAngleDeg:$,endAngleDeg:U,innerRadius:o,outerRadius:i,cx:e,cy:n}},[ct,k,D,$,U,It,Ot,R]);e.useEffect(function(){if(_&&M){var t=_._anedya.NewNode(_,M);pt(t)}},[_,M]),e.useEffect(function(){if(Nt.current=!0,dt){return s(void 0,void 0,void 0,function(){var t,e,n,r;return l(this,function(i){switch(i.label){case 0:if(Ct.current||kt.current>=3)return console.log("!node:",dt),console.log("isFetchingRef.current:",Ct.current),console.log("failureCountRef.current:",kt.current),[2];Ct.current=!0,i.label=1;case 1:return i.trys.push([1,3,4,5]),vt(!0),wt(null),[4,dt.getLatestData(S)];case 2:return t=i.sent(),Nt.current?(t.isSuccess&&t.isDataAvailable?(ft(null===(n=t.data)||void 0===n?void 0:n.value),wt("")):(ft(null),console.error("error fetching data:",t.error),wt(t.error.errorMessage)),kt.current=0,[3,5]):[2];case 3:return e=i.sent(),Nt.current?(console.error("Error fetching latest data:",e),ft(null),wt(null!==(r=null==e?void 0:e.message)&&void 0!==r?r:"Failed to fetch data"),kt.current+=1,[3,5]):[2];case 4:return Nt.current?(vt(!1),Ct.current=!1,[7]):[2];case 5:return[2]}})}),function(){Nt.current=!1}}},[dt,S]),e.useEffect(function(){if("function"==typeof ut){var t=ut(ct);t&&"object"==typeof t&&St(t)}},[ct]);var Yt=st?st(Number(ct),K):{text:String(null!=ct?ct:""),unitText:K,position:"right",unitStyle:"normal"};e.useEffect(function(){it&&it(Lt)},[Lt,it]),e.useEffect(function(){var t,e,n,r,i,o,a,u,s=jt.current;if(s){xe(s).selectAll("*").remove();var l=xe(s),c=Lt.cx,f=Lt.cy,h=Lt.outerRadius,d=Lt.innerRadius,p=Lt.valueAngleRad,g=Lt.startAngleDeg,y=Lt.endAngleDeg,v=l.append("g").attr("transform","translate(".concat(c,", ").concat(f,")")),m=Pt(g),x=Pt(y),w=ja().innerRadius(d).outerRadius(h).startAngle(m).endAngle(x)(void 0);v.append("path").attr("d",null!=w?w:"").attr("fill",null!==(t=Rt.trackColor)&&void 0!==t?t:"#e6e6e6").attr("stroke","none");var b=Pt(y-g),_=function(t){return m+(t-k)/(D-k)*b},M=(null!=I?I:[]).map(function(t){return{from:Math.max(t.from,k),to:Math.min(t.to,D),color:t.color}}).filter(function(t){return t.to>t.from}).sort(function(t,e){return t.from-e.from});if(M.forEach(function(t,e){var n=_(t.from),r=_(t.to),i=ja().innerRadius(d).outerRadius(h).startAngle(n).endAngle(r)(void 0);v.append("path").attr("d",null!=i?i:"").attr("fill",t.color).attr("stroke","none").attr("opacity",1)}),void 0!==ct){var S=ja().innerRadius(d).outerRadius(h).startAngle(m).endAngle(p)(void 0);v.append("path").attr("d",null!=S?S:"").attr("fill",null!==(e=Rt.progressColor)&&void 0!==e?e:"rgba(255,255,255,0.15)").attr("stroke",null!==(n=Rt.progressStroke)&&void 0!==n?n:"#00000000")}if(P&&void 0!==ct){var A=(d+h)/2+.15*(h-d),T=v.append("g").attr("class","needle");Ra();var C=Math.cos(p-Math.PI/2)*A,N=Math.sin(p-Math.PI/2)*A;T.append("line").attr("x1",0).attr("y1",0).attr("x2",C).attr("y2",N).attr("stroke",Y).attr("stroke-width",H).attr("stroke-linecap","round"),T.append("circle").attr("cx",0).attr("cy",0).attr("r",Math.max(3,Math.min(6,.25*(h-d)))).attr("fill",Y)}var j=at({value:ct,valueMin:k,valueMax:D}),F=v.append("g").attr("class","value-group");return F.append("text").attr("class","gauge-value-text").attr("text-anchor","middle").attr("y",-(d+h)/2*.05).style("font-size",null!==(r=Rt.fontSize)&&void 0!==r?r:"".concat(Math.round(.45*d),"px")).style("font-family",null!==(i=Rt.fontFamily)&&void 0!==i?i:"Roboto, Arial, sans-serif").style("fill",null!==(o=$t.color)&&void 0!==o?o:"#111").text(j),X&&F.append("text").attr("class","gauge-subtitle-text").attr("text-anchor","middle").attr("y",.6*(h-d)+14).style("font-size",null!==(a=Et.fontSize)&&void 0!==a?a:"12px").style("fill",null!==(u=Et.color)&&void 0!==u?u:"#666").text(X),function(){xe(s).selectAll("*").remove()}}},[Lt,I,ct,k,D,P,Y,H,at,Tt]);var Vt=function(t,e,n){return{color:"url(#".concat(n,")")}}(0,0,"redFade-randomkey"),Ht=[{min:0,max:.5,color:"rgb(181,230,29)"},{min:.5,max:1,color:"orange"},a({min:.75,max:1},Vt)],Xt=.15*Math.min(Number(It),Number(Ot)),qt=null!==(c=null===(u=null==Tt?void 0:Tt.label)||void 0===u?void 0:u.fontSize)&&void 0!==c?c:.6*Xt,Bt=null!==(h=null===(f=null==Tt?void 0:Tt.value)||void 0===f?void 0:f.fontSize)&&void 0!==h?h:1.2*Xt,Wt=null!==(p=null===(d=null==Tt?void 0:Tt.unit)||void 0===d?void 0:d.fontSize)&&void 0!==p?p:.8*Xt,Jt=a(a(a({},xu),Dt),{width:It,height:Ot}),Gt=null!==(g=null==Tt?void 0:Tt.fontFamily)&&void 0!==g?g:"Roboto",Zt=null!==(v=null===(y=xu.label)||void 0===y?void 0:y.fontFamily)&&void 0!==v?v:Gt,Qt=null!==(x=null===(m=xu.value)||void 0===m?void 0:m.fontFamily)&&void 0!==x?x:Gt,Kt=null!==(b=null===(w=xu.label)||void 0===w?void 0:w.fontFamily)&&void 0!==b?b:Gt,te=a(a(a(a({},xu.label),{fontSize:qt}),Ft),{fontFamily:Zt}),ee=a(a(a(a({},xu.value),{fontSize:Bt}),$t),{fontFamily:Qt}),ne=a(a(a(a({},xu.unit),{fontSize:Wt}),Ut),{fontFamily:Kt});return t.jsxs("div",{style:a({},Jt),children:[T&&t.jsx("h2",{style:a({},te),children:T}),yt?t.jsx("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",height:"100%"},children:t.jsx("div",{className:"spinner",style:{width:.3*Math.min(Number(It),Number(Ot)),height:.3*Math.min(Number(It),Number(Ot))}})}):xt?t.jsx("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:t.jsx("div",{style:{background:"rgba(255, 0, 0, 0.15)",border:"1px solid rgba(255, 0, 0, 0.6)",boxShadow:"rgba(149, 157, 165, 0.2) 0px 8px 24px",color:"rgba(255, 0, 0, 0.6)",textAlign:"center",borderRadius:"5px",padding:"5px"},children:xt})}):ct?t.jsx(du,{height:400,width:400,min:0,max:100,value:ct,maxAngle:U,minAngle:$,disabled:J,pointerLabel:J?"Disabled":ct+"",tickCount:Number(Z),uom:K,uomProps:{offsetText:et},labelProps:{offsetText:rt},arcSegments:Ht,mergedValueSx:ee,mergedUnitSx:ne,formatted:Yt}):ct?t.jsx(t.Fragment,{}):t.jsx("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:t.jsx("div",{style:{color:"#757575",textAlign:"center",borderRadius:"5px",padding:"5px"},children:"No data available"})})]})},exports.LatestDataWidget=R,exports.anedyaClientInit=function(t,e,n){var r,i,o,a=this,u=null!==(r=null==n?void 0:n.useGlobal)&&void 0!==r&&r,c=null!==(i=null==n?void 0:n.forceReinit)&&void 0!==i&&i,f=null!==(o=null==n?void 0:n.rateLimitMs)&&void 0!==o?o:100;if(u&&k&&!c)return k;var h=new A,d=h.NewConfig(t,e),p=h.NewClient(d),g=h.NewNode.bind(h);return h.NewNode=function(){for(var t=[],e=0;e { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/index.ts +var index_exports = {}; +__export(index_exports, { + CardWidget: () => CardWidget +}); +module.exports = __toCommonJS(index_exports); + +// src/components/CardWidget.tsx +var import_react = require("react"); +var import_tailwind_merge = require("tailwind-merge"); + +// src/themes/defaultTheme.ts +var CARD_DEFAULT_CLASSES = { + title: "text-[length:var(--anedya-card-title-size)] font-medium", + value: "text-[length:var(--anedya-card-value-size)] font-bold", + unit: "text-[length:var(--anedya-card-unit-size)]", + label: "text-[length:var(--anedya-card-label-size)]", + container: "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" +}; +var lightTheme = { + classNames: { + container: "bg-white border-slate-200", + title: "text-slate-500", + value: "text-slate-900", + label: "text-slate-400" + } +}; +var darkTheme = { + classNames: { + container: "bg-slate-900 border-slate-800", + title: "text-slate-400", + value: "text-white", + label: "text-slate-500" + } +}; + +// src/components/CardWidget.tsx +var import_jsx_runtime = require("react/jsx-runtime"); +var DEFAULT_WIDTH = 240; +var DEFAULT_MIN_WIDTH = 180; +var DEFAULT_MAX_WIDTH = 480; +function CardWidget({ + node, + variable, + title = "Latest Value", + unit, + precision, + formatValue, + labelText, + classNames = {}, + onDataChange, + theme, + className, + width, + height, + minWidth = DEFAULT_MIN_WIDTH, + maxWidth = DEFAULT_MAX_WIDTH +}) { + const [value, setValue] = (0, import_react.useState)(null); + const [timestamp, setTimestamp] = (0, import_react.useState)(null); + const [loading, setLoading] = (0, import_react.useState)(false); + const [error, setError] = (0, import_react.useState)(null); + const [dynamicProps, setDynamicProps] = (0, import_react.useState)({}); + const mountedRef = (0, import_react.useRef)(false); + const isFetchingRef = (0, import_react.useRef)(false); + (0, import_react.useEffect)(() => { + if (!node) return; + mountedRef.current = true; + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + try { + const res = await node.getLatestData(variable); + if (!mountedRef.current) return; + if (res.isSuccess && res.isDataAvailable) { + setValue(res.data.value); + setTimestamp(res.data.timestamp); + } else { + setValue(null); + setError(res.error?.errorMessage ?? "No data available"); + } + } catch (err) { + if (!mountedRef.current) return; + setValue(null); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + (0, import_react.useEffect)(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + const data = value != null && timestamp != null ? { value, timestamp } : null; + setDynamicProps(onDataChange(data) ?? {}); + }, [value, timestamp, onDataChange]); + const resolvedProps = { + title, + unit, + precision, + formatValue, + labelText, + width: width ?? DEFAULT_WIDTH, + height, + minWidth, + maxWidth, + className, + theme, + ...dynamicProps, + classNames: { + ...classNames ?? {}, + ...dynamicProps.classNames ?? {} + } + }; + const resolvedTheme = resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" ? lightTheme : resolvedProps.theme ?? lightTheme; + const resolveSlot = (slot) => (0, import_tailwind_merge.twMerge)( + CARD_DEFAULT_CLASSES[slot], + resolvedTheme.classNames[slot], + resolvedProps.classNames[slot] + ); + const displayValue = (0, import_react.useMemo)(() => { + if (value == null) return null; + if (resolvedProps.formatValue) return resolvedProps.formatValue(value); + if (resolvedProps.precision != null) + return value.toFixed(resolvedProps.precision); + return String(value); + }, [value, resolvedProps.formatValue, resolvedProps.precision]); + const displayLabel = (0, import_react.useMemo)(() => { + if (timestamp == null) return null; + if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); + const d = timestamp < 1e12 ? new Date(timestamp * 1e3) : new Date(timestamp); + return `Updated ${d.toLocaleTimeString()}`; + }, [timestamp, resolvedProps.labelText]); + return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( + "div", + { + className: (0, import_tailwind_merge.twMerge)( + "anedya-card", + resolveSlot("container"), + resolvedProps.className + ), + style: { + width: resolvedProps.width, + minWidth: resolvedProps.minWidth, + maxWidth: resolvedProps.maxWidth, + height: resolvedProps.height, + boxSizing: "border-box" + }, + children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("title"), children: resolvedProps.title }), + loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( + "div", + { + style: { + height: 36, + width: 36, + borderRadius: "50%", + border: "2px solid #cbd5e1", + borderTopColor: "#475569", + animation: "anedya-card-spin 0.8s linear infinite" + }, + children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) + } + ) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( + "span", + { + className: (0, import_tailwind_merge.twMerge)( + "inline-flex items-end justify-center gap-1", + resolveSlot("value") + ), + children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: displayValue }), + resolvedProps.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) + ] + } + ), + displayLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( + "span", + { + className: resolveSlot("label"), + children: displayLabel + } + ) + ] }) + ] + } + ); +} +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + CardWidget +}); diff --git a/dist/index.js.map b/dist/index.js.map deleted file mode 100644 index f8ac3916..00000000 --- a/dist/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sources":["../node_modules/tslib/tslib.es6.js","../node_modules/@anedyasystems/anedya-frontend-sdk/dist/index.mjs","../src/hooks/AnedyaFrontendClient.ts","../src/helpers/validate.ts","../src/components/LatestDataWidget.tsx","../src/hooks/renderLatestData.tsx","../node_modules/d3-array/src/ascending.js","../node_modules/d3-array/src/descending.js","../node_modules/d3-array/src/bisector.js","../node_modules/d3-array/src/bisect.js","../node_modules/d3-array/src/number.js","../node_modules/d3-array/src/ticks.js","../node_modules/d3-axis/src/identity.js","../node_modules/d3-axis/src/axis.js","../node_modules/d3-dispatch/src/dispatch.js","../node_modules/d3-selection/src/namespaces.js","../node_modules/d3-selection/src/namespace.js","../node_modules/d3-selection/src/creator.js","../node_modules/d3-selection/src/selector.js","../node_modules/d3-selection/src/selectorAll.js","../node_modules/d3-selection/src/selection/selectAll.js","../node_modules/d3-selection/src/array.js","../node_modules/d3-selection/src/matcher.js","../node_modules/d3-selection/src/selection/selectChild.js","../node_modules/d3-selection/src/selection/selectChildren.js","../node_modules/d3-selection/src/selection/sparse.js","../node_modules/d3-selection/src/selection/enter.js","../node_modules/d3-selection/src/selection/data.js","../node_modules/d3-selection/src/selection/sort.js","../node_modules/d3-selection/src/selection/attr.js","../node_modules/d3-selection/src/window.js","../node_modules/d3-selection/src/selection/style.js","../node_modules/d3-selection/src/selection/property.js","../node_modules/d3-selection/src/selection/classed.js","../node_modules/d3-selection/src/selection/text.js","../node_modules/d3-selection/src/selection/html.js","../node_modules/d3-selection/src/selection/raise.js","../node_modules/d3-selection/src/selection/lower.js","../node_modules/d3-selection/src/selection/insert.js","../node_modules/d3-selection/src/selection/remove.js","../node_modules/d3-selection/src/selection/clone.js","../node_modules/d3-selection/src/selection/on.js","../node_modules/d3-selection/src/selection/dispatch.js","../node_modules/d3-selection/src/selection/index.js","../node_modules/d3-selection/src/select.js","../node_modules/d3-color/src/define.js","../node_modules/d3-color/src/color.js","../node_modules/d3-selection/src/selection/select.js","../node_modules/d3-selection/src/selection/filter.js","../node_modules/d3-selection/src/constant.js","../node_modules/d3-selection/src/selection/exit.js","../node_modules/d3-selection/src/selection/join.js","../node_modules/d3-selection/src/selection/merge.js","../node_modules/d3-selection/src/selection/order.js","../node_modules/d3-selection/src/selection/call.js","../node_modules/d3-selection/src/selection/nodes.js","../node_modules/d3-selection/src/selection/node.js","../node_modules/d3-selection/src/selection/size.js","../node_modules/d3-selection/src/selection/empty.js","../node_modules/d3-selection/src/selection/each.js","../node_modules/d3-selection/src/selection/append.js","../node_modules/d3-selection/src/selection/datum.js","../node_modules/d3-selection/src/selection/iterator.js","../node_modules/d3-interpolate/src/constant.js","../node_modules/d3-interpolate/src/color.js","../node_modules/d3-interpolate/src/rgb.js","../node_modules/d3-interpolate/src/numberArray.js","../node_modules/d3-interpolate/src/array.js","../node_modules/d3-interpolate/src/date.js","../node_modules/d3-interpolate/src/number.js","../node_modules/d3-interpolate/src/object.js","../node_modules/d3-interpolate/src/string.js","../node_modules/d3-interpolate/src/value.js","../node_modules/d3-interpolate/src/round.js","../node_modules/d3-interpolate/src/transform/decompose.js","../node_modules/d3-interpolate/src/transform/parse.js","../node_modules/d3-interpolate/src/transform/index.js","../node_modules/d3-timer/src/timer.js","../node_modules/d3-timer/src/timeout.js","../node_modules/d3-transition/src/transition/schedule.js","../node_modules/d3-transition/src/transition/tween.js","../node_modules/d3-transition/src/transition/interpolate.js","../node_modules/d3-transition/src/transition/attr.js","../node_modules/d3-transition/src/transition/attrTween.js","../node_modules/d3-transition/src/transition/delay.js","../node_modules/d3-transition/src/transition/duration.js","../node_modules/d3-transition/src/transition/selection.js","../node_modules/d3-transition/src/transition/style.js","../node_modules/d3-transition/src/transition/index.js","../node_modules/d3-transition/src/transition/select.js","../node_modules/d3-transition/src/transition/selectAll.js","../node_modules/d3-transition/src/transition/filter.js","../node_modules/d3-transition/src/transition/merge.js","../node_modules/d3-transition/src/transition/transition.js","../node_modules/d3-transition/src/transition/on.js","../node_modules/d3-transition/src/transition/styleTween.js","../node_modules/d3-transition/src/transition/text.js","../node_modules/d3-transition/src/transition/textTween.js","../node_modules/d3-transition/src/transition/remove.js","../node_modules/d3-transition/src/transition/ease.js","../node_modules/d3-transition/src/transition/easeVarying.js","../node_modules/d3-transition/src/transition/end.js","../node_modules/d3-transition/src/selection/transition.js","../node_modules/d3-ease/src/cubic.js","../node_modules/d3-transition/src/selection/index.js","../node_modules/d3-transition/src/selection/interrupt.js","../node_modules/d3-transition/src/interrupt.js","../node_modules/d3-path/src/path.js","../node_modules/d3-format/src/formatDecimal.js","../node_modules/d3-format/src/exponent.js","../node_modules/d3-format/src/formatSpecifier.js","../node_modules/d3-format/src/formatPrefixAuto.js","../node_modules/d3-format/src/formatRounded.js","../node_modules/d3-format/src/formatTypes.js","../node_modules/d3-format/src/identity.js","../node_modules/d3-format/src/locale.js","../node_modules/d3-format/src/defaultLocale.js","../node_modules/d3-format/src/formatGroup.js","../node_modules/d3-format/src/formatNumerals.js","../node_modules/d3-format/src/formatTrim.js","../node_modules/d3-scale/src/init.js","../node_modules/d3-scale/src/number.js","../node_modules/d3-scale/src/continuous.js","../node_modules/d3-scale/src/constant.js","../node_modules/d3-scale/src/tickFormat.js","../node_modules/d3-format/src/precisionPrefix.js","../node_modules/d3-format/src/precisionRound.js","../node_modules/d3-format/src/precisionFixed.js","../node_modules/d3-scale/src/linear.js","../node_modules/d3-time/src/interval.js","../node_modules/d3-time/src/millisecond.js","../node_modules/d3-time/src/duration.js","../node_modules/d3-time/src/second.js","../node_modules/d3-time/src/minute.js","../node_modules/d3-time/src/hour.js","../node_modules/d3-time/src/day.js","../node_modules/d3-time/src/week.js","../node_modules/d3-time/src/month.js","../node_modules/d3-time/src/year.js","../node_modules/d3-time/src/ticks.js","../node_modules/d3-time-format/src/locale.js","../node_modules/d3-time-format/src/defaultLocale.js","../node_modules/d3-scale/src/time.js","../node_modules/d3-scale/src/nice.js","../node_modules/d3-shape/src/constant.js","../node_modules/d3-shape/src/math.js","../node_modules/d3-shape/src/path.js","../node_modules/d3-shape/src/arc.js","../node_modules/d3-shape/src/array.js","../node_modules/d3-shape/src/curve/linear.js","../node_modules/d3-shape/src/point.js","../node_modules/d3-shape/src/line.js","../node_modules/d3-shape/src/area.js","../node_modules/d3-shape/src/curve/radial.js","../node_modules/d3-shape/src/lineRadial.js","../node_modules/d3-shape/src/symbol/circle.js","../node_modules/d3-shape/src/symbol/triangle.js","../node_modules/d3-shape/src/symbol.js","../node_modules/d3-shape/src/curve/monotone.js","../node_modules/d3-zoom/src/transform.js","../src/helpers/formatDate.ts","../node_modules/style-inject/dist/style-inject.es.js","../src/components/ChartWidget.tsx","../src/components/Gauge/components/SVGBase/SVGBase.tsx","../src/components/Gauge/components/Pointer/Pointer.tsx","../src/components/Gauge/components/InvertedTriangle/InvertedTriangle.tsx","../src/components/Gauge/components/UnitOfMeasurement/UnitOfMeasurement.tsx","../src/components/Gauge/components/GaugeArc/GaugeArc.tsx","../src/components/Gauge/components/Label/Label.tsx","../src/components/Gauge/components/Gradient/Gradient.tsx","../src/components/Gauge/Gauge.tsx","../src/components/LatestDataGauge.tsx","../node_modules/d3-array/src/extent.js","../node_modules/d3-array/src/max.js","../src/components/Gauge/hooks/useGradient.tsx"],"sourcesContent":["/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\r\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nvar ownKeys = function(o) {\r\n ownKeys = Object.getOwnPropertyNames || function (o) {\r\n var ar = [];\r\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\r\n return ar;\r\n };\r\n return ownKeys(o);\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose, inner;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n if (async) inner = dispose;\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n var r, s = 0;\r\n function next() {\r\n while (r = env.stack.pop()) {\r\n try {\r\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\r\n if (r.dispose) {\r\n var result = r.dispose.call(r.value);\r\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n else s |= 1;\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\r\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\r\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\r\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\r\n });\r\n }\r\n return path;\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __esDecorate: __esDecorate,\r\n __runInitializers: __runInitializers,\r\n __propKey: __propKey,\r\n __setFunctionName: __setFunctionName,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,\r\n};\r\n","var R=class{tokenId;token;baseUrl;constructor(e,s){if(!e||e.trim()===\"\")throw new Error(\"Token ID is required\");if(!s||s.trim()===\"\")throw new Error(\"Token is required\");this.tokenId=e,this.token=s,this.baseUrl=\"https://api.anedya.io/v1\";}};var D=class{tokenId;tokenBytes;signatureVersionBytes;signatureVersion=\"v1\";authorizationMode=\"ANEDYASIGV1\";baseUrl;constructor(e){let{token:s,tokenId:a}=e;this.tokenId=a,this.signatureVersionBytes=new TextEncoder().encode(this.signatureVersion),this.tokenBytes=new TextEncoder().encode(s),this.baseUrl=e.baseUrl;}};var T=class{constructor(e,s,a,u=1e4,c=\"desc\"){this.variable=e;this.from=s;this.to=a;this.limit=u;this.order=c;if(c!==\"asc\"&&c!==\"desc\")throw new Error(\"Invalid order value. It should be either 'asc' or 'desc'.\");if(u<1)throw new Error(\"Invalid limit value. It should be at least 1.\");if(s>a)throw new Error(\"Invalid time range. 'from' should be less than or equal to 'to'.\")}},p=class{isSuccess;error;isDataAvailable;data;count;startTime;endTime;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.isDataAvailable=false,this.data=null,this.count=0,this.startTime=0,this.endTime=0;}},g=class{isSuccess;error;isDataAvailable;data;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.isDataAvailable=false,this.data=null;}},N=class{constructor(e,s,a,u){this.namespace=e;this.key=s;this.value=a;this.type=u;if(this.namespace.scope!==\"global\"&&this.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\");if(this.type!==\"string\"&&this.type!==\"binary\"&&this.type!==\"float\"&&this.type!==\"boolean\")throw new Error(\"Invalid type value. It should be either 'string', 'binary', 'float', or 'boolean'.\")}},h=class{isSuccess;error;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"};}},C=class{constructor(e,s){this.namespace=e;this.key=s;if(this.namespace.scope!==\"global\"&&this.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\")}},b=class{isSuccess;error;namespace;key;value;type;size;modified;created;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.namespace={scope:\"\",id:\"\"},this.key=\"\",this.value=void 0,this.type=\"\",this.size=0,this.modified=0,this.created=0;}},K=class{constructor(e,s){this.namespace=e;this.key=s;if(this.namespace.scope!==\"global\"&&this.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\")}},A=class{isSuccess;error;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"};}},x=class{constructor(e,s,a,u,c){this.filter=e;this.orderby=s;this.order=a;this.limit=u;this.offset=c;if(this.filter.namespace.scope!==\"global\"&&this.filter.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\")}},I=class{isSuccess;error;count;totalCount;data;next;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.count=0,this.totalCount=0,this.data=void 0,this.next=0;}},S=class{isSuccess;error;data;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.data=void 0;}},v=class{constructor(e,s){this.time=e;this.variable=s;if(!Number.isFinite(e)||e<=0)throw new Error(\"Invalid time: must be a positive number (UNIX timestamp).\");let a=Math.floor(Date.now()/1e3);if(e>a)throw new Error(\"Invalid time: timestamp cannot be in the future.\");if(!s||typeof s!=\"string\")throw new Error(\"Invalid variable: must be a non-empty string.\")}},f=class{isSuccess;error;count;data;constructor(){this.error={errorMessage:\"\",reasonCode:\"\"},this.isSuccess=false,this.count=0,this.data=[];}};var m=async(o,e,s)=>{try{let u=new TextEncoder().encode(JSON.stringify(o)),c=await crypto.subtle.digest(\"SHA-256\",u),l=new Uint8Array(c),y=new Uint8Array(8);new DataView(y.buffer).setBigUint64(0,BigInt(s),!1);let d=new Uint8Array(l.length+y.length+e.signatureVersionBytes.length+e.tokenBytes.length);d.set(l,0),d.set(y,l.length),d.set(e.signatureVersionBytes,l.length+y.length),d.set(e.tokenBytes,l.length+y.length+e.signatureVersionBytes.length);let i=await crypto.subtle.digest(\"SHA-256\",d);return Array.from(new Uint8Array(i)).map(t=>t.toString(16).padStart(2,\"0\")).join(\"\")}catch(a){console.log(a);}};var G=async(o,e,s,a)=>{let u=`${o}/data/getData`,c={nodes:s,variable:a.variable,from:Math.floor(a.from/1e3),to:Math.floor(a.to/1e3),limit:a.limit,order:a.order},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new p;try{let t=await i.json();if(r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isDataAvailable=!1,r.data=null,t.success){let n=t.data;n==null||n==null||Object.keys(n).length===0?r.isDataAvailable=!1:s.length===1?(n=n[s.toString()],r.data=n,r.isDataAvailable=!0):(r.data=n,r.isDataAvailable=!0);}return r.count=t.count,r.startTime=t.startTime,r.endTime=t.endTime,r}catch{return r.isSuccess=!1,r.error.reasonCode=i.status.toString(),r.error.errorMessage=i.statusText,r}}catch(d){throw console.error(\"Error during Get data request:\",d),d}},k=async(o,e,s,a)=>{let u=`${o}/data/latest`,c={nodes:s,variable:a.variable},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new g;try{let t=await i.json();if(r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isDataAvailable=!1,r.data=null,t.success){let n=t.data;n==null||n==null||Object.keys(n).length===0?r.isDataAvailable=!1:s.length===1?(n=n[s.toString()],r.data=n,r.isDataAvailable=!0):(r.data=n,r.isDataAvailable=!0);}return r}catch{return r.isSuccess=!1,r.error.reasonCode=i.status.toString(),r.error.errorMessage=i.statusText,r}}catch(d){throw console.error(\"Error during get latest data request:\",d),d}};var V=async(o,e,s,a)=>{let u=`${o}/valuestore/setValue`,c;a.namespace.scope===\"node\"?c=s[0]:c=a.namespace.id;let l={namespace:{scope:a.namespace.scope,id:c},key:a.key,value:a.value,type:a.type},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new h;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during set key: \",i),i}},O=async(o,e,s,a)=>{let u=`${o}/valuestore/getValue`,c;a.namespace.scope===\"node\"?c=s[0]:c=a.namespace.id;let l={namespace:{scope:a.namespace.scope,id:c},key:a.key},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new b;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t.namespace=n.namespace,t.key=n.key,t.value=n.value,t.type=n.type,t.size=n.size,t.modified=n.modified,t.created=n.created,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during get key request: \",i),i}},q=async(o,e,s,a)=>{let u=`${o}/valuestore/delete`,c;a.namespace.scope===\"node\"?c=s[0]:c=a.namespace.id;let l={namespace:{scope:a.namespace.scope,id:c},key:a.key},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new A;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during fetch operation:\",i),i}},M=async(o,e,s,a)=>{let u=`${o}/valuestore/scan`,c;a.filter.namespace.scope===\"node\"?c=s[0]:c=a.filter.namespace.id;let l={filter:{namespace:{scope:a.filter.namespace.scope,id:c}},orderby:a.orderby,order:a.order,limit:a.limit,offset:a.offset},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new I;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t.count=n.count,t.totalCount=n.totalCount,t.data=n.data,t.next=n.next,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during scan vs operation: \",i),i}};var U=async(o,e,s,a)=>{let u=`${o}/health/status`,c={nodes:s,lastContactThreshold:a},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new S;try{let t=await i.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isSuccess&&(s.length===1?r.data=t.data[s[0]]:r.data=t.data),r}catch{return r.isSuccess=!1,r.error.errorMessage=i.statusText,r.error.reasonCode=i.status.toString(),r}}catch(d){throw console.error(\"Error during fetch operation:\",d),d}};var P=async(o,e,s,a)=>{let u=`${o}/data/snapshot`,c={nodes:s,time:a?.time,variable:a?.variable},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new f;try{let t=await i.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isSuccess&&(s.length===1?r.data=t.data.filter(n=>n.node===s[0]):r.data=t.data,r.count=t.count),r}catch{return r.isSuccess=!1,r.error.errorMessage=i.statusText,r.error.reasonCode=i.status.toString(),r}}catch(d){throw console.error(\"Error during fetch operation:\",d),d}};var w=class{#e;#t;#r;constructor(e,s){let{baseUrl:a,tokenId:u,tokenBytes:c,signatureVersionBytes:l,signatureVersion:y,authorizationMode:d}=e;this.#e=s,this.#t=a,this.#r={tokenId:u,tokenBytes:c,signatureVersion:y,signatureVersionBytes:l,authorizationMode:d};}getNodeId(){return this.#e}async getData(e){return await G(this.#t,this.#r,[this.#e],e)}async getLatestData(e){let s={variable:e};return await k(this.#t,this.#r,[this.#e],s)}async setKey(e){return await V(this.#t,this.#r,[this.#e],e)}async getKey(e){return await O(this.#t,this.#r,[this.#e],e)}async deleteKey(e){return await q(this.#t,this.#r,[this.#e],e)}async scanKeys(e){return await M(this.#t,this.#r,[this.#e],e)}async getDeviceStatus(e){return await U(this.#t,this.#r,[this.#e],e)}async getSnapshot(e){return await P(this.#t,this.#r,[this.#e],e)}};var E=class{NewConfig(e,s){return new R(e,s)}NewClient(e){return new D(e)}NewNode(e,s){return new w(e,s)}};var B=(s=>(s.GLOBAL=\"global\",s.NODE=\"node\",s))(B||{}),X=(u=>(u.STRING=\"string\",u.BINARY=\"binary\",u.FLOAT=\"float\",u.BOOLEAN=\"boolean\",u))(X||{});var _={Success:-1,Unknown:0,Failure:1,HttpRequestError:3,HttpRequestTimeout:4,keyNotFound:5};function z(o){return Object.fromEntries(Object.entries(_).map(([s,a])=>[a,s]))[o]||\"UnknownErrorCode\"}\nexport{E as Anedya,X as AnedyaDataType,K as AnedyaDeleteKeyReq,A as AnedyaDeleteKeyResp,_ as AnedyaError,T as AnedyaGetDataReq,p as AnedyaGetDataResp,S as AnedyaGetDeviceStatusResp,C as AnedyaGetKeyReq,b as AnedyaGetKeyResp,g as AnedyaGetLatestDataResp,v as AnedyaGetSnapshotReq,f as AnedyaGetSnapshotResp,x as AnedyaScanKeysReq,I as AnedyaScanKeysResp,B as AnedyaScope,N as AnedyaSetKeyReq,h as AnedyaSetKeyResp,z as getAnedyaErrorMessage};//# sourceMappingURL=index.mjs.map\n//# sourceMappingURL=index.mjs.map","import { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\nimport { AnedyaClient } from \"../components/types\";\n\nlet globalClient: AnedyaClient | null = null;\n\n// --- Global rate limiter map ---\ntype RateLimiter = {\n lastCallTime: number;\n interval: number;\n};\n\nconst nodeRateLimiters = new Map();\n\n\n// --- Type for InitOptions ---\ninterface InitOptions {\n useGlobal?: boolean;\n forceReinit?: boolean;\n rateLimitMs?: number; // βœ… configurable rate limit interval\n}\n\n/**\n * Initialize the Anedya client and optionally store globally.\n *\n * @returns client\n */\n\nexport function anedyaClientInit(\n tokenId: string,\n token: string,\n options?: InitOptions\n): AnedyaClient {\n const useGlobal = options?.useGlobal ?? false;\n const forceReinit = options?.forceReinit ?? false;\n const rateLimitMs = options?.rateLimitMs ?? 100; // βœ… default: 10 seconds\n\n if (useGlobal && globalClient && !forceReinit) {\n return globalClient;\n }\n\n const anedya = new Anedya();\n const config = anedya.NewConfig(tokenId, token);\n const client = anedya.NewClient(config);\n\n // --- Patch NewNode with per-node rate limiter ---\n const originalNewNode: (...args: any[]) => any = anedya.NewNode.bind(anedya);\n\n anedya.NewNode = (...args: any[]): any => {\n const node = originalNewNode(...args); // βœ… now properly typed\n\n // Extract nodeId (second argument)\n const nodeId = typeof args[1] === \"string\" ? args[1] : `unknown-${Date.now()}`;\n\n const limiter =\n nodeRateLimiters.get(nodeId) || {\n lastCallTime: 0,\n interval: rateLimitMs, // βœ… use configurable rate limit\n };\n nodeRateLimiters.set(nodeId, limiter);\n\n if (node.getLatestData) {\n const originalGetLatestData: (...params: any[]) => Promise =\n node.getLatestData.bind(node);\n\n node.getLatestData = async (...params: any[]): Promise => {\n const now = Date.now();\n const elapsed = now - limiter.lastCallTime;\n\n if (elapsed < limiter.interval) {\n const wait = limiter.interval - elapsed;\n console.warn(\n `⏳ Rate limited for node ${nodeId}: waiting ${wait}ms before next call`\n );\n await new Promise((r) => setTimeout(r, wait));\n }\n\n limiter.lastCallTime = Date.now();\n\n try {\n return await originalGetLatestData(...params);\n } catch (err) {\n console.error(`⚠️ API call failed for node ${nodeId}:`, err);\n throw err;\n }\n };\n }\n\n return node;\n };\n\n // Attach wrapped anedya instance to client\n (client as any)._anedya = anedya;\n\n if (useGlobal) {\n globalClient = client;\n }\n\n return client;\n}\n\n\n/**\n * Retrieve the globally initialized Anedya instance and client.\n */\nexport function getAnedyaClient(): AnedyaClient {\n if (!globalClient) {\n throw new Error(\n \"Anedya client not initialized! Call anedyaClientInit first.\"\n );\n }\n return globalClient;\n}\n\n/**\n * Clear the global Anedya client (for logout/reset).\n */\nexport function resetAnedyaClient(): void {\n globalClient = null;\n}\n","export function validateRequiredProps(\n componentName: string,\n props: Record,\n required: string[]\n) {\n const missing = required.filter((key) => props[key] === undefined);\n\n if (missing.length === 0) return;\n\n const message = `[${componentName}] Missing required prop(s): ${missing.join(\n \", \"\n )}`;\n\n\n\n console.error(message);\n \n}\n","import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\nimport { CSSProperties } from \"react\";\nimport { validateRequiredProps } from \"../helpers/validate\";\n// --- Default color ranges ---\nconst defaultColorRanges = [\n { max: 40, color: \"#008000\" },\n { max: 100, color: \"#FFA500\" },\n { max: Infinity, color: \"#FF2C2C\" },\n];\n\ntype WidgetState = {\n value?: number;\n loading: boolean;\n error?: string|null;\n};\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\ninterface DisplayTextResult {\n text: string;\n unitText?: string;\n position?: UnitPosition;\n unitStyle?: UnitStyle;\n}\n\ntype DisplayTextFormatter = (\n value: number,\n unit?: string\n) => DisplayTextResult;\n\n// --- Default styles ---\ninterface StyleSet {\n container?: CSSProperties;\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\n fontFamily?: string; // optional global font family for all 3\n}\n\n\ntype StylesInput =\n | StyleSet\n | ((state: WidgetState) => StyleSet);\n\n\n\nconst defaultFontFamily = \"Roboto, sans-serif\";\n\nconst defaultStyles: Required = {\n container: {\n width: 400,\n height: 250,\n padding: 2,\n margin: 0,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",\n borderRadius: 10,\n boxSizing: \"border-box\",\n background: \"rgb(248, 249, 250)\",\n border: \"1px solid rgba(211, 216, 220, 1)\",\n//'linear-gradient(to right, rgb(47, 99, 255), rgb(20, 110, 180))'\n fontFamily: defaultFontFamily,\n color:\"#000000\",\n gap: 2,\n textAlign: \"center\",\n },\n label: { fontWeight: 500, color: \"#000000\", fontFamily: defaultFontFamily },\n value: { fontWeight: 700, color: \"#000000\", fontFamily: defaultFontFamily },\n unit: { fontWeight: 400, color: \"#000000\", fontFamily: defaultFontFamily },\n fontFamily: defaultFontFamily,\n \n};\n\n// --- Helper: get color from range ---\nconst getColorFromRange = (value: number, ranges = defaultColorRanges) => {\n const range = ranges.find((r) => value <= r.max);\n return range?.color ?? \"#333\";\n};\n\n// --- Helper: normalize sx for TypeScript ---\nconst normalizeSx = (\n sx: Record | undefined\n): Record => {\n if (!sx) return {};\n if (Array.isArray(sx)) return Object.assign({}, ...sx);\n if (typeof sx === \"function\") return sx({}) as Record;\n return sx as Record;\n};\n\n// --- Circuit Breaker Config ---\nconst MAX_FAILURES = 3;\n\n// --- Rate limiter settings ---\nconst MIN_FETCH_INTERVAL = 10000; // 10 seconds between fetches\n\n// --- Props ---\ninterface WidgetProps {\n client: any;\n nodeId: string;\n variable: string;\n title?: string;\n unit?: string;\n styles?: StylesInput;\n displayText?: DisplayTextFormatter;\n colorRange?: typeof defaultColorRanges;\n colorRangeCallback?: (value: number, defaultColor: string) => string;\n onStyleChange?:(value:number) =>{}\n}\n\nexport const LatestDataWidgetComponent: React.FC = ({\n client,\n nodeId,\n variable,\n title = \"Latest Data\",\n unit = \"\",\n styles = {},\n displayText,\n colorRange,\n colorRangeCallback,\n onStyleChange\n}) => {\n validateRequiredProps(\"LatestDataWidget\", { client, nodeId, variable }, [\n \"client\",\n \"nodeId\",\n \"variable\",\n ]);\n\n\n const [data, setData] = useState(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(null);\n const [node, setNode] = useState(null); // <-- store node in state\n\n // --- Preventing stale closures / infinite renders ---\n\n const isFetchingRef = useRef(false);\n const failureCountRef = useRef(0);\n const mountedRef = useRef(false);\n const lastFetchRef = useRef(0);\n\n // Build a state object to pass into the callback styles\nconst widgetState = { data, loading, error };\n\n// Resolve function or static style object\nconst [dynamicStyles, setDynamicStyles] = useState>({});\n\nconst baseResolvedStyles =\n typeof styles === \"function\" ? styles(widgetState) : styles || {};\n\nconst resolvedStyles = {\n container: { ...baseResolvedStyles.container, ...dynamicStyles?.container },\n label: { ...baseResolvedStyles.label, ...dynamicStyles?.label },\n value: { ...baseResolvedStyles.value, ...dynamicStyles?.value },\n unit: { ...baseResolvedStyles.unit, ...dynamicStyles?.unit },\n fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily,\n};\nconst formatted: DisplayTextResult = displayText\n ? displayText(Number(data), unit)\n : {\n text: String(data ?? \"\"),\n unitText: unit,\n position: \"right\",\n unitStyle: \"normal\",\n };\n\n\n \n\n useEffect(() => {\n if (client && nodeId) {\n const anedya = (client as any)._anedya as Anedya; // retrieve wrapped instance\n const createdNode = anedya.NewNode(client, nodeId);\n setNode(createdNode);\n }\n }, [client, nodeId]);\n\n // --- Fetch data once safely ---\n useEffect(() => {\n mountedRef.current = true;\n if (!node) return;\n const fetchData = async () => {\n if (isFetchingRef.current || failureCountRef.current >= MAX_FAILURES) {\n //rate limiter ----> in client\n console.log(\"!node:\", node);\n console.log(\"isFetchingRef.current:\", isFetchingRef.current);\n console.log(\"failureCountRef.current:\", failureCountRef.current);\n return;\n } // don't try if node not ready or if an api call is being currently made already\n\n isFetchingRef.current = true;\n try {\n setLoading(true);\n setError(null);\n const res = await node.getLatestData(variable);\n\n if (!mountedRef.current) return; // <-- SAFE, stops state update if unmounted\n\n if (res.isSuccess && res.isDataAvailable) {\n\n setData(res.data?.value);\n setError(\"\");\n } else {\n setData(null);\n console.error(\"error fetching data:\", res.error);\n setError(res.error.errorMessage);\n }\n failureCountRef.current = 0; // reset on success\n } catch (err: any) {\n if (!mountedRef.current) return;\n console.error(\"Error fetching latest data:\", err);\n setData(null);\n setError(err?.message ?? \"Failed to fetch data\");\n failureCountRef.current += 1;\n } finally {\n if (!mountedRef.current) return;\n setLoading(false);\n isFetchingRef.current = false;\n }\n };\n fetchData();\n\n return () => {\n mountedRef.current = false;\n };\n }, [node, variable]);\n\n\n // Whenever value changes, allow user to modify styles dynamically\n useEffect(() => {\n if (typeof onStyleChange === \"function\") {\n const updated = onStyleChange(data);\n if (updated && typeof updated === \"object\") {\n setDynamicStyles(updated);\n }\n }\n }, [data]);\n\n // --- Normalize styles ---\n const containerSx = normalizeSx(resolvedStyles?.container);\n const labelSx = normalizeSx(resolvedStyles?.label);\n const valueSx = normalizeSx(resolvedStyles?.value);\n const unitSx = normalizeSx(resolvedStyles?.unit);\n\n // --- Container dimensions with TypeScript-safe default ---\n const containerDefaults: any = defaultStyles.container!;\n const width = containerSx.width ?? containerDefaults.width;\n const height = containerSx.height ?? containerDefaults.height;\n\n // --- Scaled font sizes ---\n const baseFont = Math.min(Number(width), Number(height)) * 0.15;\n\n // --- Compute font sizes dynamically if not provided by user ---\n const labelFont = (resolvedStyles?.label as any)?.fontSize ?? baseFont * 0.6;\n\n const valueFont = (resolvedStyles?.value as any)?.fontSize ?? baseFont * 3;\n\n const unitFont = (resolvedStyles?.unit as any)?.fontSize ?? baseFont * 0.8;\n\n // --- Font family handling ---\n const globalFontFamily = resolvedStyles?.fontFamily ?? \"Roboto\";\n const labelFontFamily = labelSx.fontFamily ?? globalFontFamily;\n const valueFontFamily = valueSx.fontFamily ?? globalFontFamily;\n const unitFontFamily = unitSx.fontFamily ?? globalFontFamily;\n\n // --- Gap scaling ---\n const containerGap = (containerSx as any).gap ?? baseFont * 0.2; // scale gap if user didn't pass one\n\n // --- Compute dynamic text color ---\n const finalRange = colorRange ?? defaultColorRanges;\n let textColor = getColorFromRange(Number(data) ?? 0, finalRange);\n if (colorRangeCallback) {\n textColor = colorRangeCallback(Number(data) ?? 0, textColor);\n }\n\n // --- Merge styles safely ---\n const mergedContainerSx: CSSProperties = {\n ...defaultStyles.container,\n ...containerSx,\n \n gap: containerGap,\n\n };\n const mergedLabelSx: CSSProperties = {\n ...defaultStyles.label,\n fontSize: labelFont,\n ...labelSx,\n fontFamily: labelFontFamily,\n };\n const mergedValueSx: CSSProperties = {\n ...defaultStyles.value,\n fontSize: valueFont,\n color: textColor,\n ...valueSx,\n fontFamily: valueFontFamily,\n };\n const mergedUnitSx: CSSProperties = {\n ...defaultStyles.unit,\n fontSize: unitFont,\n ...unitSx,\n fontFamily: unitFontFamily,\n };\n\n\n const renderUnitText = (text: string, style: UnitStyle) => {\n switch (style) {\n case \"superscript\":\n return {text};\n case \"subscript\":\n return {text};\n default:\n return {text};\n }\n};\n\n\n return (\n\n \n {title &&

{title}

}\n\n\n {loading ? (\n \n
\n
\n ) : error ? (\n
\n \n{error}\n
\n\n \n ) : !data ? (\n
\n \n{ \"No data available\"}\n
\n\n \n ) : (\n <>\n
\n \n {/* Unit LEFT */}\n {formatted.unitText &&\n formatted.position === \"left\" &&\n
\n\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n\n {/* VALUE */}\n
{formatted.text}
\n\n {/* Unit RIGHT */}\n {formatted.unitText &&\n formatted.position === \"right\" &&\n
\n \n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n\n {/* Unit TOP */}\n {formatted.unitText &&\n formatted.position === \"top\" &&\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n\n {/* Unit BOTTOM */}\n {formatted.unitText &&\n formatted.position === \"bottom\" &&\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n
\n \n )}\n \n \n\n\n );\n};\n\nexport default LatestDataWidgetComponent;\n","import React, { useState, useCallback, JSX } from \"react\";\nimport { LatestDataWidgetComponent } from \"../components/LatestDataWidget\";\nimport { AnedyaClient } from \"../components/types\";\nimport { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\n\n// --- Default color ranges ---\nconst defaultColorRanges = [\n { max: 20, color: \"red\" },\n { max: 50, color: \"yellow\" },\n { max: Infinity, color: \"green\" },\n];\nimport { CSSProperties } from \"react\";\n\n// --- Default styles ---\ninterface StyleSet {\n container?: CSSProperties;\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\n}\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\ninterface DisplayTextResult {\n text: string;\n unitText?: string;\n position?: UnitPosition;\n unitStyle?: UnitStyle;\n}\n\ntype DisplayTextFormatter = (\n value: number,\n unit?: string\n) => DisplayTextResult;\n\n\ninterface LatestDataWidgetProps {\n client: AnedyaClient;\n nodeId: string;\n variable: string;\n title?: string;\n unit?: string;\n styles?: StyleSet;\n colorRange?: typeof defaultColorRanges;\n colorRangeCallback?: (value: number, defaultColor: string) => string;\n fontFamily? : string;\n displayText?: DisplayTextFormatter;\n onStyleChange?:(value:number)=>{}\n}\n\nexport const LatestDataWidget: React.FC = React.memo((\n {\n client,\n nodeId,\n variable,\n title,\n unit,\n styles = {},\n colorRange,\n colorRangeCallback,\n displayText,\n onStyleChange\n } \n) => {\n return (\n <>\n \n \n \n \n );\n}, \n(prev, next) => JSON.stringify(prev) === JSON.stringify(next))\n","export default function ascending(a, b) {\n return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n","export default function descending(a, b) {\n return a == null || b == null ? NaN\n : b < a ? -1\n : b > a ? 1\n : b >= a ? 0\n : NaN;\n}\n","import ascending from \"./ascending.js\";\nimport descending from \"./descending.js\";\n\nexport default function bisector(f) {\n let compare1, compare2, delta;\n\n // If an accessor is specified, promote it to a comparator. In this case we\n // can test whether the search value is (self-) comparable. We can’t do this\n // for a comparator (except for specific, known comparators) because we can’t\n // tell if the comparator is symmetric, and an asymmetric comparator can’t be\n // used to test whether a single value is comparable.\n if (f.length !== 2) {\n compare1 = ascending;\n compare2 = (d, x) => ascending(f(d), x);\n delta = (d, x) => f(d) - x;\n } else {\n compare1 = f === ascending || f === descending ? f : zero;\n compare2 = f;\n delta = f;\n }\n\n function left(a, x, lo = 0, hi = a.length) {\n if (lo < hi) {\n if (compare1(x, x) !== 0) return hi;\n do {\n const mid = (lo + hi) >>> 1;\n if (compare2(a[mid], x) < 0) lo = mid + 1;\n else hi = mid;\n } while (lo < hi);\n }\n return lo;\n }\n\n function right(a, x, lo = 0, hi = a.length) {\n if (lo < hi) {\n if (compare1(x, x) !== 0) return hi;\n do {\n const mid = (lo + hi) >>> 1;\n if (compare2(a[mid], x) <= 0) lo = mid + 1;\n else hi = mid;\n } while (lo < hi);\n }\n return lo;\n }\n\n function center(a, x, lo = 0, hi = a.length) {\n const i = left(a, x, lo, hi - 1);\n return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;\n }\n\n return {left, center, right};\n}\n\nfunction zero() {\n return 0;\n}\n","import ascending from \"./ascending.js\";\nimport bisector from \"./bisector.js\";\nimport number from \"./number.js\";\n\nconst ascendingBisect = bisector(ascending);\nexport const bisectRight = ascendingBisect.right;\nexport const bisectLeft = ascendingBisect.left;\nexport const bisectCenter = bisector(number).center;\nexport default bisectRight;\n","export default function number(x) {\n return x === null ? NaN : +x;\n}\n\nexport function* numbers(values, valueof) {\n if (valueof === undefined) {\n for (let value of values) {\n if (value != null && (value = +value) >= value) {\n yield value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {\n yield value;\n }\n }\n }\n}\n","const e10 = Math.sqrt(50),\n e5 = Math.sqrt(10),\n e2 = Math.sqrt(2);\n\nfunction tickSpec(start, stop, count) {\n const step = (stop - start) / Math.max(0, count),\n power = Math.floor(Math.log10(step)),\n error = step / Math.pow(10, power),\n factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;\n let i1, i2, inc;\n if (power < 0) {\n inc = Math.pow(10, -power) / factor;\n i1 = Math.round(start * inc);\n i2 = Math.round(stop * inc);\n if (i1 / inc < start) ++i1;\n if (i2 / inc > stop) --i2;\n inc = -inc;\n } else {\n inc = Math.pow(10, power) * factor;\n i1 = Math.round(start / inc);\n i2 = Math.round(stop / inc);\n if (i1 * inc < start) ++i1;\n if (i2 * inc > stop) --i2;\n }\n if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);\n return [i1, i2, inc];\n}\n\nexport default function ticks(start, stop, count) {\n stop = +stop, start = +start, count = +count;\n if (!(count > 0)) return [];\n if (start === stop) return [start];\n const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);\n if (!(i2 >= i1)) return [];\n const n = i2 - i1 + 1, ticks = new Array(n);\n if (reverse) {\n if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) / -inc;\n else for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) * inc;\n } else {\n if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) / -inc;\n else for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) * inc;\n }\n return ticks;\n}\n\nexport function tickIncrement(start, stop, count) {\n stop = +stop, start = +start, count = +count;\n return tickSpec(start, stop, count)[2];\n}\n\nexport function tickStep(start, stop, count) {\n stop = +stop, start = +start, count = +count;\n const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);\n return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);\n}\n","export default function(x) {\n return x;\n}\n","import identity from \"./identity.js\";\n\nvar top = 1,\n right = 2,\n bottom = 3,\n left = 4,\n epsilon = 1e-6;\n\nfunction translateX(x) {\n return \"translate(\" + x + \",0)\";\n}\n\nfunction translateY(y) {\n return \"translate(0,\" + y + \")\";\n}\n\nfunction number(scale) {\n return d => +scale(d);\n}\n\nfunction center(scale, offset) {\n offset = Math.max(0, scale.bandwidth() - offset * 2) / 2;\n if (scale.round()) offset = Math.round(offset);\n return d => +scale(d) + offset;\n}\n\nfunction entering() {\n return !this.__axis;\n}\n\nfunction axis(orient, scale) {\n var tickArguments = [],\n tickValues = null,\n tickFormat = null,\n tickSizeInner = 6,\n tickSizeOuter = 6,\n tickPadding = 3,\n offset = typeof window !== \"undefined\" && window.devicePixelRatio > 1 ? 0 : 0.5,\n k = orient === top || orient === left ? -1 : 1,\n x = orient === left || orient === right ? \"x\" : \"y\",\n transform = orient === top || orient === bottom ? translateX : translateY;\n\n function axis(context) {\n var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,\n format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity) : tickFormat,\n spacing = Math.max(tickSizeInner, 0) + tickPadding,\n range = scale.range(),\n range0 = +range[0] + offset,\n range1 = +range[range.length - 1] + offset,\n position = (scale.bandwidth ? center : number)(scale.copy(), offset),\n selection = context.selection ? context.selection() : context,\n path = selection.selectAll(\".domain\").data([null]),\n tick = selection.selectAll(\".tick\").data(values, scale).order(),\n tickExit = tick.exit(),\n tickEnter = tick.enter().append(\"g\").attr(\"class\", \"tick\"),\n line = tick.select(\"line\"),\n text = tick.select(\"text\");\n\n path = path.merge(path.enter().insert(\"path\", \".tick\")\n .attr(\"class\", \"domain\")\n .attr(\"stroke\", \"currentColor\"));\n\n tick = tick.merge(tickEnter);\n\n line = line.merge(tickEnter.append(\"line\")\n .attr(\"stroke\", \"currentColor\")\n .attr(x + \"2\", k * tickSizeInner));\n\n text = text.merge(tickEnter.append(\"text\")\n .attr(\"fill\", \"currentColor\")\n .attr(x, k * spacing)\n .attr(\"dy\", orient === top ? \"0em\" : orient === bottom ? \"0.71em\" : \"0.32em\"));\n\n if (context !== selection) {\n path = path.transition(context);\n tick = tick.transition(context);\n line = line.transition(context);\n text = text.transition(context);\n\n tickExit = tickExit.transition(context)\n .attr(\"opacity\", epsilon)\n .attr(\"transform\", function(d) { return isFinite(d = position(d)) ? transform(d + offset) : this.getAttribute(\"transform\"); });\n\n tickEnter\n .attr(\"opacity\", epsilon)\n .attr(\"transform\", function(d) { var p = this.parentNode.__axis; return transform((p && isFinite(p = p(d)) ? p : position(d)) + offset); });\n }\n\n tickExit.remove();\n\n path\n .attr(\"d\", orient === left || orient === right\n ? (tickSizeOuter ? \"M\" + k * tickSizeOuter + \",\" + range0 + \"H\" + offset + \"V\" + range1 + \"H\" + k * tickSizeOuter : \"M\" + offset + \",\" + range0 + \"V\" + range1)\n : (tickSizeOuter ? \"M\" + range0 + \",\" + k * tickSizeOuter + \"V\" + offset + \"H\" + range1 + \"V\" + k * tickSizeOuter : \"M\" + range0 + \",\" + offset + \"H\" + range1));\n\n tick\n .attr(\"opacity\", 1)\n .attr(\"transform\", function(d) { return transform(position(d) + offset); });\n\n line\n .attr(x + \"2\", k * tickSizeInner);\n\n text\n .attr(x, k * spacing)\n .text(format);\n\n selection.filter(entering)\n .attr(\"fill\", \"none\")\n .attr(\"font-size\", 10)\n .attr(\"font-family\", \"sans-serif\")\n .attr(\"text-anchor\", orient === right ? \"start\" : orient === left ? \"end\" : \"middle\");\n\n selection\n .each(function() { this.__axis = position; });\n }\n\n axis.scale = function(_) {\n return arguments.length ? (scale = _, axis) : scale;\n };\n\n axis.ticks = function() {\n return tickArguments = Array.from(arguments), axis;\n };\n\n axis.tickArguments = function(_) {\n return arguments.length ? (tickArguments = _ == null ? [] : Array.from(_), axis) : tickArguments.slice();\n };\n\n axis.tickValues = function(_) {\n return arguments.length ? (tickValues = _ == null ? null : Array.from(_), axis) : tickValues && tickValues.slice();\n };\n\n axis.tickFormat = function(_) {\n return arguments.length ? (tickFormat = _, axis) : tickFormat;\n };\n\n axis.tickSize = function(_) {\n return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;\n };\n\n axis.tickSizeInner = function(_) {\n return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;\n };\n\n axis.tickSizeOuter = function(_) {\n return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;\n };\n\n axis.tickPadding = function(_) {\n return arguments.length ? (tickPadding = +_, axis) : tickPadding;\n };\n\n axis.offset = function(_) {\n return arguments.length ? (offset = +_, axis) : offset;\n };\n\n return axis;\n}\n\nexport function axisTop(scale) {\n return axis(top, scale);\n}\n\nexport function axisRight(scale) {\n return axis(right, scale);\n}\n\nexport function axisBottom(scale) {\n return axis(bottom, scale);\n}\n\nexport function axisLeft(scale) {\n return axis(left, scale);\n}\n","var noop = {value: () => {}};\n\nfunction dispatch() {\n for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {\n if (!(t = arguments[i] + \"\") || (t in _) || /[\\s.]/.test(t)) throw new Error(\"illegal type: \" + t);\n _[t] = [];\n }\n return new Dispatch(_);\n}\n\nfunction Dispatch(_) {\n this._ = _;\n}\n\nfunction parseTypenames(typenames, types) {\n return typenames.trim().split(/^|\\s+/).map(function(t) {\n var name = \"\", i = t.indexOf(\".\");\n if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);\n if (t && !types.hasOwnProperty(t)) throw new Error(\"unknown type: \" + t);\n return {type: t, name: name};\n });\n}\n\nDispatch.prototype = dispatch.prototype = {\n constructor: Dispatch,\n on: function(typename, callback) {\n var _ = this._,\n T = parseTypenames(typename + \"\", _),\n t,\n i = -1,\n n = T.length;\n\n // If no callback was specified, return the callback of the given type and name.\n if (arguments.length < 2) {\n while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;\n return;\n }\n\n // If a type was specified, set the callback for the given type and name.\n // Otherwise, if a null callback was specified, remove callbacks of the given name.\n if (callback != null && typeof callback !== \"function\") throw new Error(\"invalid callback: \" + callback);\n while (++i < n) {\n if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);\n else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);\n }\n\n return this;\n },\n copy: function() {\n var copy = {}, _ = this._;\n for (var t in _) copy[t] = _[t].slice();\n return new Dispatch(copy);\n },\n call: function(type, that) {\n if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];\n if (!this._.hasOwnProperty(type)) throw new Error(\"unknown type: \" + type);\n for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);\n },\n apply: function(type, that, args) {\n if (!this._.hasOwnProperty(type)) throw new Error(\"unknown type: \" + type);\n for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);\n }\n};\n\nfunction get(type, name) {\n for (var i = 0, n = type.length, c; i < n; ++i) {\n if ((c = type[i]).name === name) {\n return c.value;\n }\n }\n}\n\nfunction set(type, name, callback) {\n for (var i = 0, n = type.length; i < n; ++i) {\n if (type[i].name === name) {\n type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));\n break;\n }\n }\n if (callback != null) type.push({name: name, value: callback});\n return type;\n}\n\nexport default dispatch;\n","export var xhtml = \"http://www.w3.org/1999/xhtml\";\n\nexport default {\n svg: \"http://www.w3.org/2000/svg\",\n xhtml: xhtml,\n xlink: \"http://www.w3.org/1999/xlink\",\n xml: \"http://www.w3.org/XML/1998/namespace\",\n xmlns: \"http://www.w3.org/2000/xmlns/\"\n};\n","import namespaces from \"./namespaces.js\";\n\nexport default function(name) {\n var prefix = name += \"\", i = prefix.indexOf(\":\");\n if (i >= 0 && (prefix = name.slice(0, i)) !== \"xmlns\") name = name.slice(i + 1);\n return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins\n}\n","import namespace from \"./namespace.js\";\nimport {xhtml} from \"./namespaces.js\";\n\nfunction creatorInherit(name) {\n return function() {\n var document = this.ownerDocument,\n uri = this.namespaceURI;\n return uri === xhtml && document.documentElement.namespaceURI === xhtml\n ? document.createElement(name)\n : document.createElementNS(uri, name);\n };\n}\n\nfunction creatorFixed(fullname) {\n return function() {\n return this.ownerDocument.createElementNS(fullname.space, fullname.local);\n };\n}\n\nexport default function(name) {\n var fullname = namespace(name);\n return (fullname.local\n ? creatorFixed\n : creatorInherit)(fullname);\n}\n","function none() {}\n\nexport default function(selector) {\n return selector == null ? none : function() {\n return this.querySelector(selector);\n };\n}\n","function empty() {\n return [];\n}\n\nexport default function(selector) {\n return selector == null ? empty : function() {\n return this.querySelectorAll(selector);\n };\n}\n","import {Selection} from \"./index.js\";\nimport array from \"../array.js\";\nimport selectorAll from \"../selectorAll.js\";\n\nfunction arrayAll(select) {\n return function() {\n return array(select.apply(this, arguments));\n };\n}\n\nexport default function(select) {\n if (typeof select === \"function\") select = arrayAll(select);\n else select = selectorAll(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n subgroups.push(select.call(node, node.__data__, i, group));\n parents.push(node);\n }\n }\n }\n\n return new Selection(subgroups, parents);\n}\n","// Given something array like (or null), returns something that is strictly an\n// array. This is used to ensure that array-like objects passed to d3.selectAll\n// or selection.selectAll are converted into proper arrays when creating a\n// selection; we don’t ever want to create a selection backed by a live\n// HTMLCollection or NodeList. However, note that selection.selectAll will use a\n// static NodeList as a group, since it safely derived from querySelectorAll.\nexport default function array(x) {\n return x == null ? [] : Array.isArray(x) ? x : Array.from(x);\n}\n","export default function(selector) {\n return function() {\n return this.matches(selector);\n };\n}\n\nexport function childMatcher(selector) {\n return function(node) {\n return node.matches(selector);\n };\n}\n\n","import {childMatcher} from \"../matcher.js\";\n\nvar find = Array.prototype.find;\n\nfunction childFind(match) {\n return function() {\n return find.call(this.children, match);\n };\n}\n\nfunction childFirst() {\n return this.firstElementChild;\n}\n\nexport default function(match) {\n return this.select(match == null ? childFirst\n : childFind(typeof match === \"function\" ? match : childMatcher(match)));\n}\n","import {childMatcher} from \"../matcher.js\";\n\nvar filter = Array.prototype.filter;\n\nfunction children() {\n return Array.from(this.children);\n}\n\nfunction childrenFilter(match) {\n return function() {\n return filter.call(this.children, match);\n };\n}\n\nexport default function(match) {\n return this.selectAll(match == null ? children\n : childrenFilter(typeof match === \"function\" ? match : childMatcher(match)));\n}\n","export default function(update) {\n return new Array(update.length);\n}\n","import sparse from \"./sparse.js\";\nimport {Selection} from \"./index.js\";\n\nexport default function() {\n return new Selection(this._enter || this._groups.map(sparse), this._parents);\n}\n\nexport function EnterNode(parent, datum) {\n this.ownerDocument = parent.ownerDocument;\n this.namespaceURI = parent.namespaceURI;\n this._next = null;\n this._parent = parent;\n this.__data__ = datum;\n}\n\nEnterNode.prototype = {\n constructor: EnterNode,\n appendChild: function(child) { return this._parent.insertBefore(child, this._next); },\n insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },\n querySelector: function(selector) { return this._parent.querySelector(selector); },\n querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }\n};\n","import {Selection} from \"./index.js\";\nimport {EnterNode} from \"./enter.js\";\nimport constant from \"../constant.js\";\n\nfunction bindIndex(parent, group, enter, update, exit, data) {\n var i = 0,\n node,\n groupLength = group.length,\n dataLength = data.length;\n\n // Put any non-null nodes that fit into update.\n // Put any null nodes into enter.\n // Put any remaining data into enter.\n for (; i < dataLength; ++i) {\n if (node = group[i]) {\n node.__data__ = data[i];\n update[i] = node;\n } else {\n enter[i] = new EnterNode(parent, data[i]);\n }\n }\n\n // Put any non-null nodes that don’t fit into exit.\n for (; i < groupLength; ++i) {\n if (node = group[i]) {\n exit[i] = node;\n }\n }\n}\n\nfunction bindKey(parent, group, enter, update, exit, data, key) {\n var i,\n node,\n nodeByKeyValue = new Map,\n groupLength = group.length,\n dataLength = data.length,\n keyValues = new Array(groupLength),\n keyValue;\n\n // Compute the key for each node.\n // If multiple nodes have the same key, the duplicates are added to exit.\n for (i = 0; i < groupLength; ++i) {\n if (node = group[i]) {\n keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + \"\";\n if (nodeByKeyValue.has(keyValue)) {\n exit[i] = node;\n } else {\n nodeByKeyValue.set(keyValue, node);\n }\n }\n }\n\n // Compute the key for each datum.\n // If there a node associated with this key, join and add it to update.\n // If there is not (or the key is a duplicate), add it to enter.\n for (i = 0; i < dataLength; ++i) {\n keyValue = key.call(parent, data[i], i, data) + \"\";\n if (node = nodeByKeyValue.get(keyValue)) {\n update[i] = node;\n node.__data__ = data[i];\n nodeByKeyValue.delete(keyValue);\n } else {\n enter[i] = new EnterNode(parent, data[i]);\n }\n }\n\n // Add any remaining nodes that were not bound to data to exit.\n for (i = 0; i < groupLength; ++i) {\n if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) {\n exit[i] = node;\n }\n }\n}\n\nfunction datum(node) {\n return node.__data__;\n}\n\nexport default function(value, key) {\n if (!arguments.length) return Array.from(this, datum);\n\n var bind = key ? bindKey : bindIndex,\n parents = this._parents,\n groups = this._groups;\n\n if (typeof value !== \"function\") value = constant(value);\n\n for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {\n var parent = parents[j],\n group = groups[j],\n groupLength = group.length,\n data = arraylike(value.call(parent, parent && parent.__data__, j, parents)),\n dataLength = data.length,\n enterGroup = enter[j] = new Array(dataLength),\n updateGroup = update[j] = new Array(dataLength),\n exitGroup = exit[j] = new Array(groupLength);\n\n bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);\n\n // Now connect the enter nodes to their following update node, such that\n // appendChild can insert the materialized enter node before this node,\n // rather than at the end of the parent node.\n for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {\n if (previous = enterGroup[i0]) {\n if (i0 >= i1) i1 = i0 + 1;\n while (!(next = updateGroup[i1]) && ++i1 < dataLength);\n previous._next = next || null;\n }\n }\n }\n\n update = new Selection(update, parents);\n update._enter = enter;\n update._exit = exit;\n return update;\n}\n\n// Given some data, this returns an array-like view of it: an object that\n// exposes a length property and allows numeric indexing. Note that unlike\n// selectAll, this isn’t worried about β€œlive” collections because the resulting\n// array will only be used briefly while data is being bound. (It is possible to\n// cause the data to change while iterating by using a key function, but please\n// don’t; we’d rather avoid a gratuitous copy.)\nfunction arraylike(data) {\n return typeof data === \"object\" && \"length\" in data\n ? data // Array, TypedArray, NodeList, array-like\n : Array.from(data); // Map, Set, iterable, string, or anything else\n}\n","import {Selection} from \"./index.js\";\n\nexport default function(compare) {\n if (!compare) compare = ascending;\n\n function compareNode(a, b) {\n return a && b ? compare(a.__data__, b.__data__) : !a - !b;\n }\n\n for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n sortgroup[i] = node;\n }\n }\n sortgroup.sort(compareNode);\n }\n\n return new Selection(sortgroups, this._parents).order();\n}\n\nfunction ascending(a, b) {\n return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n","import namespace from \"../namespace.js\";\n\nfunction attrRemove(name) {\n return function() {\n this.removeAttribute(name);\n };\n}\n\nfunction attrRemoveNS(fullname) {\n return function() {\n this.removeAttributeNS(fullname.space, fullname.local);\n };\n}\n\nfunction attrConstant(name, value) {\n return function() {\n this.setAttribute(name, value);\n };\n}\n\nfunction attrConstantNS(fullname, value) {\n return function() {\n this.setAttributeNS(fullname.space, fullname.local, value);\n };\n}\n\nfunction attrFunction(name, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) this.removeAttribute(name);\n else this.setAttribute(name, v);\n };\n}\n\nfunction attrFunctionNS(fullname, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) this.removeAttributeNS(fullname.space, fullname.local);\n else this.setAttributeNS(fullname.space, fullname.local, v);\n };\n}\n\nexport default function(name, value) {\n var fullname = namespace(name);\n\n if (arguments.length < 2) {\n var node = this.node();\n return fullname.local\n ? node.getAttributeNS(fullname.space, fullname.local)\n : node.getAttribute(fullname);\n }\n\n return this.each((value == null\n ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === \"function\"\n ? (fullname.local ? attrFunctionNS : attrFunction)\n : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));\n}\n","export default function(node) {\n return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node\n || (node.document && node) // node is a Window\n || node.defaultView; // node is a Document\n}\n","import defaultView from \"../window.js\";\n\nfunction styleRemove(name) {\n return function() {\n this.style.removeProperty(name);\n };\n}\n\nfunction styleConstant(name, value, priority) {\n return function() {\n this.style.setProperty(name, value, priority);\n };\n}\n\nfunction styleFunction(name, value, priority) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) this.style.removeProperty(name);\n else this.style.setProperty(name, v, priority);\n };\n}\n\nexport default function(name, value, priority) {\n return arguments.length > 1\n ? this.each((value == null\n ? styleRemove : typeof value === \"function\"\n ? styleFunction\n : styleConstant)(name, value, priority == null ? \"\" : priority))\n : styleValue(this.node(), name);\n}\n\nexport function styleValue(node, name) {\n return node.style.getPropertyValue(name)\n || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);\n}\n","function propertyRemove(name) {\n return function() {\n delete this[name];\n };\n}\n\nfunction propertyConstant(name, value) {\n return function() {\n this[name] = value;\n };\n}\n\nfunction propertyFunction(name, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) delete this[name];\n else this[name] = v;\n };\n}\n\nexport default function(name, value) {\n return arguments.length > 1\n ? this.each((value == null\n ? propertyRemove : typeof value === \"function\"\n ? propertyFunction\n : propertyConstant)(name, value))\n : this.node()[name];\n}\n","function classArray(string) {\n return string.trim().split(/^|\\s+/);\n}\n\nfunction classList(node) {\n return node.classList || new ClassList(node);\n}\n\nfunction ClassList(node) {\n this._node = node;\n this._names = classArray(node.getAttribute(\"class\") || \"\");\n}\n\nClassList.prototype = {\n add: function(name) {\n var i = this._names.indexOf(name);\n if (i < 0) {\n this._names.push(name);\n this._node.setAttribute(\"class\", this._names.join(\" \"));\n }\n },\n remove: function(name) {\n var i = this._names.indexOf(name);\n if (i >= 0) {\n this._names.splice(i, 1);\n this._node.setAttribute(\"class\", this._names.join(\" \"));\n }\n },\n contains: function(name) {\n return this._names.indexOf(name) >= 0;\n }\n};\n\nfunction classedAdd(node, names) {\n var list = classList(node), i = -1, n = names.length;\n while (++i < n) list.add(names[i]);\n}\n\nfunction classedRemove(node, names) {\n var list = classList(node), i = -1, n = names.length;\n while (++i < n) list.remove(names[i]);\n}\n\nfunction classedTrue(names) {\n return function() {\n classedAdd(this, names);\n };\n}\n\nfunction classedFalse(names) {\n return function() {\n classedRemove(this, names);\n };\n}\n\nfunction classedFunction(names, value) {\n return function() {\n (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);\n };\n}\n\nexport default function(name, value) {\n var names = classArray(name + \"\");\n\n if (arguments.length < 2) {\n var list = classList(this.node()), i = -1, n = names.length;\n while (++i < n) if (!list.contains(names[i])) return false;\n return true;\n }\n\n return this.each((typeof value === \"function\"\n ? classedFunction : value\n ? classedTrue\n : classedFalse)(names, value));\n}\n","function textRemove() {\n this.textContent = \"\";\n}\n\nfunction textConstant(value) {\n return function() {\n this.textContent = value;\n };\n}\n\nfunction textFunction(value) {\n return function() {\n var v = value.apply(this, arguments);\n this.textContent = v == null ? \"\" : v;\n };\n}\n\nexport default function(value) {\n return arguments.length\n ? this.each(value == null\n ? textRemove : (typeof value === \"function\"\n ? textFunction\n : textConstant)(value))\n : this.node().textContent;\n}\n","function htmlRemove() {\n this.innerHTML = \"\";\n}\n\nfunction htmlConstant(value) {\n return function() {\n this.innerHTML = value;\n };\n}\n\nfunction htmlFunction(value) {\n return function() {\n var v = value.apply(this, arguments);\n this.innerHTML = v == null ? \"\" : v;\n };\n}\n\nexport default function(value) {\n return arguments.length\n ? this.each(value == null\n ? htmlRemove : (typeof value === \"function\"\n ? htmlFunction\n : htmlConstant)(value))\n : this.node().innerHTML;\n}\n","function raise() {\n if (this.nextSibling) this.parentNode.appendChild(this);\n}\n\nexport default function() {\n return this.each(raise);\n}\n","function lower() {\n if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);\n}\n\nexport default function() {\n return this.each(lower);\n}\n","import creator from \"../creator.js\";\nimport selector from \"../selector.js\";\n\nfunction constantNull() {\n return null;\n}\n\nexport default function(name, before) {\n var create = typeof name === \"function\" ? name : creator(name),\n select = before == null ? constantNull : typeof before === \"function\" ? before : selector(before);\n return this.select(function() {\n return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);\n });\n}\n","function remove() {\n var parent = this.parentNode;\n if (parent) parent.removeChild(this);\n}\n\nexport default function() {\n return this.each(remove);\n}\n","function selection_cloneShallow() {\n var clone = this.cloneNode(false), parent = this.parentNode;\n return parent ? parent.insertBefore(clone, this.nextSibling) : clone;\n}\n\nfunction selection_cloneDeep() {\n var clone = this.cloneNode(true), parent = this.parentNode;\n return parent ? parent.insertBefore(clone, this.nextSibling) : clone;\n}\n\nexport default function(deep) {\n return this.select(deep ? selection_cloneDeep : selection_cloneShallow);\n}\n","function contextListener(listener) {\n return function(event) {\n listener.call(this, event, this.__data__);\n };\n}\n\nfunction parseTypenames(typenames) {\n return typenames.trim().split(/^|\\s+/).map(function(t) {\n var name = \"\", i = t.indexOf(\".\");\n if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);\n return {type: t, name: name};\n });\n}\n\nfunction onRemove(typename) {\n return function() {\n var on = this.__on;\n if (!on) return;\n for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {\n if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {\n this.removeEventListener(o.type, o.listener, o.options);\n } else {\n on[++i] = o;\n }\n }\n if (++i) on.length = i;\n else delete this.__on;\n };\n}\n\nfunction onAdd(typename, value, options) {\n return function() {\n var on = this.__on, o, listener = contextListener(value);\n if (on) for (var j = 0, m = on.length; j < m; ++j) {\n if ((o = on[j]).type === typename.type && o.name === typename.name) {\n this.removeEventListener(o.type, o.listener, o.options);\n this.addEventListener(o.type, o.listener = listener, o.options = options);\n o.value = value;\n return;\n }\n }\n this.addEventListener(typename.type, listener, options);\n o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options};\n if (!on) this.__on = [o];\n else on.push(o);\n };\n}\n\nexport default function(typename, value, options) {\n var typenames = parseTypenames(typename + \"\"), i, n = typenames.length, t;\n\n if (arguments.length < 2) {\n var on = this.node().__on;\n if (on) for (var j = 0, m = on.length, o; j < m; ++j) {\n for (i = 0, o = on[j]; i < n; ++i) {\n if ((t = typenames[i]).type === o.type && t.name === o.name) {\n return o.value;\n }\n }\n }\n return;\n }\n\n on = value ? onAdd : onRemove;\n for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));\n return this;\n}\n","import defaultView from \"../window.js\";\n\nfunction dispatchEvent(node, type, params) {\n var window = defaultView(node),\n event = window.CustomEvent;\n\n if (typeof event === \"function\") {\n event = new event(type, params);\n } else {\n event = window.document.createEvent(\"Event\");\n if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;\n else event.initEvent(type, false, false);\n }\n\n node.dispatchEvent(event);\n}\n\nfunction dispatchConstant(type, params) {\n return function() {\n return dispatchEvent(this, type, params);\n };\n}\n\nfunction dispatchFunction(type, params) {\n return function() {\n return dispatchEvent(this, type, params.apply(this, arguments));\n };\n}\n\nexport default function(type, params) {\n return this.each((typeof params === \"function\"\n ? dispatchFunction\n : dispatchConstant)(type, params));\n}\n","import selection_select from \"./select.js\";\nimport selection_selectAll from \"./selectAll.js\";\nimport selection_selectChild from \"./selectChild.js\";\nimport selection_selectChildren from \"./selectChildren.js\";\nimport selection_filter from \"./filter.js\";\nimport selection_data from \"./data.js\";\nimport selection_enter from \"./enter.js\";\nimport selection_exit from \"./exit.js\";\nimport selection_join from \"./join.js\";\nimport selection_merge from \"./merge.js\";\nimport selection_order from \"./order.js\";\nimport selection_sort from \"./sort.js\";\nimport selection_call from \"./call.js\";\nimport selection_nodes from \"./nodes.js\";\nimport selection_node from \"./node.js\";\nimport selection_size from \"./size.js\";\nimport selection_empty from \"./empty.js\";\nimport selection_each from \"./each.js\";\nimport selection_attr from \"./attr.js\";\nimport selection_style from \"./style.js\";\nimport selection_property from \"./property.js\";\nimport selection_classed from \"./classed.js\";\nimport selection_text from \"./text.js\";\nimport selection_html from \"./html.js\";\nimport selection_raise from \"./raise.js\";\nimport selection_lower from \"./lower.js\";\nimport selection_append from \"./append.js\";\nimport selection_insert from \"./insert.js\";\nimport selection_remove from \"./remove.js\";\nimport selection_clone from \"./clone.js\";\nimport selection_datum from \"./datum.js\";\nimport selection_on from \"./on.js\";\nimport selection_dispatch from \"./dispatch.js\";\nimport selection_iterator from \"./iterator.js\";\n\nexport var root = [null];\n\nexport function Selection(groups, parents) {\n this._groups = groups;\n this._parents = parents;\n}\n\nfunction selection() {\n return new Selection([[document.documentElement]], root);\n}\n\nfunction selection_selection() {\n return this;\n}\n\nSelection.prototype = selection.prototype = {\n constructor: Selection,\n select: selection_select,\n selectAll: selection_selectAll,\n selectChild: selection_selectChild,\n selectChildren: selection_selectChildren,\n filter: selection_filter,\n data: selection_data,\n enter: selection_enter,\n exit: selection_exit,\n join: selection_join,\n merge: selection_merge,\n selection: selection_selection,\n order: selection_order,\n sort: selection_sort,\n call: selection_call,\n nodes: selection_nodes,\n node: selection_node,\n size: selection_size,\n empty: selection_empty,\n each: selection_each,\n attr: selection_attr,\n style: selection_style,\n property: selection_property,\n classed: selection_classed,\n text: selection_text,\n html: selection_html,\n raise: selection_raise,\n lower: selection_lower,\n append: selection_append,\n insert: selection_insert,\n remove: selection_remove,\n clone: selection_clone,\n datum: selection_datum,\n on: selection_on,\n dispatch: selection_dispatch,\n [Symbol.iterator]: selection_iterator\n};\n\nexport default selection;\n","import {Selection, root} from \"./selection/index.js\";\n\nexport default function(selector) {\n return typeof selector === \"string\"\n ? new Selection([[document.querySelector(selector)]], [document.documentElement])\n : new Selection([[selector]], root);\n}\n","export default function(constructor, factory, prototype) {\n constructor.prototype = factory.prototype = prototype;\n prototype.constructor = constructor;\n}\n\nexport function extend(parent, definition) {\n var prototype = Object.create(parent.prototype);\n for (var key in definition) prototype[key] = definition[key];\n return prototype;\n}\n","import define, {extend} from \"./define.js\";\n\nexport function Color() {}\n\nexport var darker = 0.7;\nexport var brighter = 1 / darker;\n\nvar reI = \"\\\\s*([+-]?\\\\d+)\\\\s*\",\n reN = \"\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+(?:[eE][+-]?\\\\d+)?)\\\\s*\",\n reP = \"\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+(?:[eE][+-]?\\\\d+)?)%\\\\s*\",\n reHex = /^#([0-9a-f]{3,8})$/,\n reRgbInteger = new RegExp(`^rgb\\\\(${reI},${reI},${reI}\\\\)$`),\n reRgbPercent = new RegExp(`^rgb\\\\(${reP},${reP},${reP}\\\\)$`),\n reRgbaInteger = new RegExp(`^rgba\\\\(${reI},${reI},${reI},${reN}\\\\)$`),\n reRgbaPercent = new RegExp(`^rgba\\\\(${reP},${reP},${reP},${reN}\\\\)$`),\n reHslPercent = new RegExp(`^hsl\\\\(${reN},${reP},${reP}\\\\)$`),\n reHslaPercent = new RegExp(`^hsla\\\\(${reN},${reP},${reP},${reN}\\\\)$`);\n\nvar named = {\n aliceblue: 0xf0f8ff,\n antiquewhite: 0xfaebd7,\n aqua: 0x00ffff,\n aquamarine: 0x7fffd4,\n azure: 0xf0ffff,\n beige: 0xf5f5dc,\n bisque: 0xffe4c4,\n black: 0x000000,\n blanchedalmond: 0xffebcd,\n blue: 0x0000ff,\n blueviolet: 0x8a2be2,\n brown: 0xa52a2a,\n burlywood: 0xdeb887,\n cadetblue: 0x5f9ea0,\n chartreuse: 0x7fff00,\n chocolate: 0xd2691e,\n coral: 0xff7f50,\n cornflowerblue: 0x6495ed,\n cornsilk: 0xfff8dc,\n crimson: 0xdc143c,\n cyan: 0x00ffff,\n darkblue: 0x00008b,\n darkcyan: 0x008b8b,\n darkgoldenrod: 0xb8860b,\n darkgray: 0xa9a9a9,\n darkgreen: 0x006400,\n darkgrey: 0xa9a9a9,\n darkkhaki: 0xbdb76b,\n darkmagenta: 0x8b008b,\n darkolivegreen: 0x556b2f,\n darkorange: 0xff8c00,\n darkorchid: 0x9932cc,\n darkred: 0x8b0000,\n darksalmon: 0xe9967a,\n darkseagreen: 0x8fbc8f,\n darkslateblue: 0x483d8b,\n darkslategray: 0x2f4f4f,\n darkslategrey: 0x2f4f4f,\n darkturquoise: 0x00ced1,\n darkviolet: 0x9400d3,\n deeppink: 0xff1493,\n deepskyblue: 0x00bfff,\n dimgray: 0x696969,\n dimgrey: 0x696969,\n dodgerblue: 0x1e90ff,\n firebrick: 0xb22222,\n floralwhite: 0xfffaf0,\n forestgreen: 0x228b22,\n fuchsia: 0xff00ff,\n gainsboro: 0xdcdcdc,\n ghostwhite: 0xf8f8ff,\n gold: 0xffd700,\n goldenrod: 0xdaa520,\n gray: 0x808080,\n green: 0x008000,\n greenyellow: 0xadff2f,\n grey: 0x808080,\n honeydew: 0xf0fff0,\n hotpink: 0xff69b4,\n indianred: 0xcd5c5c,\n indigo: 0x4b0082,\n ivory: 0xfffff0,\n khaki: 0xf0e68c,\n lavender: 0xe6e6fa,\n lavenderblush: 0xfff0f5,\n lawngreen: 0x7cfc00,\n lemonchiffon: 0xfffacd,\n lightblue: 0xadd8e6,\n lightcoral: 0xf08080,\n lightcyan: 0xe0ffff,\n lightgoldenrodyellow: 0xfafad2,\n lightgray: 0xd3d3d3,\n lightgreen: 0x90ee90,\n lightgrey: 0xd3d3d3,\n lightpink: 0xffb6c1,\n lightsalmon: 0xffa07a,\n lightseagreen: 0x20b2aa,\n lightskyblue: 0x87cefa,\n lightslategray: 0x778899,\n lightslategrey: 0x778899,\n lightsteelblue: 0xb0c4de,\n lightyellow: 0xffffe0,\n lime: 0x00ff00,\n limegreen: 0x32cd32,\n linen: 0xfaf0e6,\n magenta: 0xff00ff,\n maroon: 0x800000,\n mediumaquamarine: 0x66cdaa,\n mediumblue: 0x0000cd,\n mediumorchid: 0xba55d3,\n mediumpurple: 0x9370db,\n mediumseagreen: 0x3cb371,\n mediumslateblue: 0x7b68ee,\n mediumspringgreen: 0x00fa9a,\n mediumturquoise: 0x48d1cc,\n mediumvioletred: 0xc71585,\n midnightblue: 0x191970,\n mintcream: 0xf5fffa,\n mistyrose: 0xffe4e1,\n moccasin: 0xffe4b5,\n navajowhite: 0xffdead,\n navy: 0x000080,\n oldlace: 0xfdf5e6,\n olive: 0x808000,\n olivedrab: 0x6b8e23,\n orange: 0xffa500,\n orangered: 0xff4500,\n orchid: 0xda70d6,\n palegoldenrod: 0xeee8aa,\n palegreen: 0x98fb98,\n paleturquoise: 0xafeeee,\n palevioletred: 0xdb7093,\n papayawhip: 0xffefd5,\n peachpuff: 0xffdab9,\n peru: 0xcd853f,\n pink: 0xffc0cb,\n plum: 0xdda0dd,\n powderblue: 0xb0e0e6,\n purple: 0x800080,\n rebeccapurple: 0x663399,\n red: 0xff0000,\n rosybrown: 0xbc8f8f,\n royalblue: 0x4169e1,\n saddlebrown: 0x8b4513,\n salmon: 0xfa8072,\n sandybrown: 0xf4a460,\n seagreen: 0x2e8b57,\n seashell: 0xfff5ee,\n sienna: 0xa0522d,\n silver: 0xc0c0c0,\n skyblue: 0x87ceeb,\n slateblue: 0x6a5acd,\n slategray: 0x708090,\n slategrey: 0x708090,\n snow: 0xfffafa,\n springgreen: 0x00ff7f,\n steelblue: 0x4682b4,\n tan: 0xd2b48c,\n teal: 0x008080,\n thistle: 0xd8bfd8,\n tomato: 0xff6347,\n turquoise: 0x40e0d0,\n violet: 0xee82ee,\n wheat: 0xf5deb3,\n white: 0xffffff,\n whitesmoke: 0xf5f5f5,\n yellow: 0xffff00,\n yellowgreen: 0x9acd32\n};\n\ndefine(Color, color, {\n copy(channels) {\n return Object.assign(new this.constructor, this, channels);\n },\n displayable() {\n return this.rgb().displayable();\n },\n hex: color_formatHex, // Deprecated! Use color.formatHex.\n formatHex: color_formatHex,\n formatHex8: color_formatHex8,\n formatHsl: color_formatHsl,\n formatRgb: color_formatRgb,\n toString: color_formatRgb\n});\n\nfunction color_formatHex() {\n return this.rgb().formatHex();\n}\n\nfunction color_formatHex8() {\n return this.rgb().formatHex8();\n}\n\nfunction color_formatHsl() {\n return hslConvert(this).formatHsl();\n}\n\nfunction color_formatRgb() {\n return this.rgb().formatRgb();\n}\n\nexport default function color(format) {\n var m, l;\n format = (format + \"\").trim().toLowerCase();\n return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000\n : l === 3 ? new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) // #f00\n : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000\n : l === 4 ? rgba((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff) // #f000\n : null) // invalid hex\n : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)\n : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)\n : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)\n : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)\n : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)\n : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)\n : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins\n : format === \"transparent\" ? new Rgb(NaN, NaN, NaN, 0)\n : null;\n}\n\nfunction rgbn(n) {\n return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);\n}\n\nfunction rgba(r, g, b, a) {\n if (a <= 0) r = g = b = NaN;\n return new Rgb(r, g, b, a);\n}\n\nexport function rgbConvert(o) {\n if (!(o instanceof Color)) o = color(o);\n if (!o) return new Rgb;\n o = o.rgb();\n return new Rgb(o.r, o.g, o.b, o.opacity);\n}\n\nexport function rgb(r, g, b, opacity) {\n return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);\n}\n\nexport function Rgb(r, g, b, opacity) {\n this.r = +r;\n this.g = +g;\n this.b = +b;\n this.opacity = +opacity;\n}\n\ndefine(Rgb, rgb, extend(Color, {\n brighter(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);\n },\n darker(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);\n },\n rgb() {\n return this;\n },\n clamp() {\n return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));\n },\n displayable() {\n return (-0.5 <= this.r && this.r < 255.5)\n && (-0.5 <= this.g && this.g < 255.5)\n && (-0.5 <= this.b && this.b < 255.5)\n && (0 <= this.opacity && this.opacity <= 1);\n },\n hex: rgb_formatHex, // Deprecated! Use color.formatHex.\n formatHex: rgb_formatHex,\n formatHex8: rgb_formatHex8,\n formatRgb: rgb_formatRgb,\n toString: rgb_formatRgb\n}));\n\nfunction rgb_formatHex() {\n return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;\n}\n\nfunction rgb_formatHex8() {\n return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;\n}\n\nfunction rgb_formatRgb() {\n const a = clampa(this.opacity);\n return `${a === 1 ? \"rgb(\" : \"rgba(\"}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? \")\" : `, ${a})`}`;\n}\n\nfunction clampa(opacity) {\n return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));\n}\n\nfunction clampi(value) {\n return Math.max(0, Math.min(255, Math.round(value) || 0));\n}\n\nfunction hex(value) {\n value = clampi(value);\n return (value < 16 ? \"0\" : \"\") + value.toString(16);\n}\n\nfunction hsla(h, s, l, a) {\n if (a <= 0) h = s = l = NaN;\n else if (l <= 0 || l >= 1) h = s = NaN;\n else if (s <= 0) h = NaN;\n return new Hsl(h, s, l, a);\n}\n\nexport function hslConvert(o) {\n if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);\n if (!(o instanceof Color)) o = color(o);\n if (!o) return new Hsl;\n if (o instanceof Hsl) return o;\n o = o.rgb();\n var r = o.r / 255,\n g = o.g / 255,\n b = o.b / 255,\n min = Math.min(r, g, b),\n max = Math.max(r, g, b),\n h = NaN,\n s = max - min,\n l = (max + min) / 2;\n if (s) {\n if (r === max) h = (g - b) / s + (g < b) * 6;\n else if (g === max) h = (b - r) / s + 2;\n else h = (r - g) / s + 4;\n s /= l < 0.5 ? max + min : 2 - max - min;\n h *= 60;\n } else {\n s = l > 0 && l < 1 ? 0 : h;\n }\n return new Hsl(h, s, l, o.opacity);\n}\n\nexport function hsl(h, s, l, opacity) {\n return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);\n}\n\nfunction Hsl(h, s, l, opacity) {\n this.h = +h;\n this.s = +s;\n this.l = +l;\n this.opacity = +opacity;\n}\n\ndefine(Hsl, hsl, extend(Color, {\n brighter(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Hsl(this.h, this.s, this.l * k, this.opacity);\n },\n darker(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Hsl(this.h, this.s, this.l * k, this.opacity);\n },\n rgb() {\n var h = this.h % 360 + (this.h < 0) * 360,\n s = isNaN(h) || isNaN(this.s) ? 0 : this.s,\n l = this.l,\n m2 = l + (l < 0.5 ? l : 1 - l) * s,\n m1 = 2 * l - m2;\n return new Rgb(\n hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),\n hsl2rgb(h, m1, m2),\n hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),\n this.opacity\n );\n },\n clamp() {\n return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));\n },\n displayable() {\n return (0 <= this.s && this.s <= 1 || isNaN(this.s))\n && (0 <= this.l && this.l <= 1)\n && (0 <= this.opacity && this.opacity <= 1);\n },\n formatHsl() {\n const a = clampa(this.opacity);\n return `${a === 1 ? \"hsl(\" : \"hsla(\"}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? \")\" : `, ${a})`}`;\n }\n}));\n\nfunction clamph(value) {\n value = (value || 0) % 360;\n return value < 0 ? value + 360 : value;\n}\n\nfunction clampt(value) {\n return Math.max(0, Math.min(1, value || 0));\n}\n\n/* From FvD 13.37, CSS Color Module Level 3 */\nfunction hsl2rgb(h, m1, m2) {\n return (h < 60 ? m1 + (m2 - m1) * h / 60\n : h < 180 ? m2\n : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60\n : m1) * 255;\n}\n","import {Selection} from \"./index.js\";\nimport selector from \"../selector.js\";\n\nexport default function(select) {\n if (typeof select !== \"function\") select = selector(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {\n if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {\n if (\"__data__\" in node) subnode.__data__ = node.__data__;\n subgroup[i] = subnode;\n }\n }\n }\n\n return new Selection(subgroups, this._parents);\n}\n","import {Selection} from \"./index.js\";\nimport matcher from \"../matcher.js\";\n\nexport default function(match) {\n if (typeof match !== \"function\") match = matcher(match);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {\n if ((node = group[i]) && match.call(node, node.__data__, i, group)) {\n subgroup.push(node);\n }\n }\n }\n\n return new Selection(subgroups, this._parents);\n}\n","export default function(x) {\n return function() {\n return x;\n };\n}\n","import sparse from \"./sparse.js\";\nimport {Selection} from \"./index.js\";\n\nexport default function() {\n return new Selection(this._exit || this._groups.map(sparse), this._parents);\n}\n","export default function(onenter, onupdate, onexit) {\n var enter = this.enter(), update = this, exit = this.exit();\n if (typeof onenter === \"function\") {\n enter = onenter(enter);\n if (enter) enter = enter.selection();\n } else {\n enter = enter.append(onenter + \"\");\n }\n if (onupdate != null) {\n update = onupdate(update);\n if (update) update = update.selection();\n }\n if (onexit == null) exit.remove(); else onexit(exit);\n return enter && update ? enter.merge(update).order() : update;\n}\n","import {Selection} from \"./index.js\";\n\nexport default function(context) {\n var selection = context.selection ? context.selection() : context;\n\n for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {\n for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {\n if (node = group0[i] || group1[i]) {\n merge[i] = node;\n }\n }\n }\n\n for (; j < m0; ++j) {\n merges[j] = groups0[j];\n }\n\n return new Selection(merges, this._parents);\n}\n","export default function() {\n\n for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {\n for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {\n if (node = group[i]) {\n if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);\n next = node;\n }\n }\n }\n\n return this;\n}\n","export default function() {\n var callback = arguments[0];\n arguments[0] = this;\n callback.apply(null, arguments);\n return this;\n}\n","export default function() {\n return Array.from(this);\n}\n","export default function() {\n\n for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {\n for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {\n var node = group[i];\n if (node) return node;\n }\n }\n\n return null;\n}\n","export default function() {\n let size = 0;\n for (const node of this) ++size; // eslint-disable-line no-unused-vars\n return size;\n}\n","export default function() {\n return !this.node();\n}\n","export default function(callback) {\n\n for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {\n for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {\n if (node = group[i]) callback.call(node, node.__data__, i, group);\n }\n }\n\n return this;\n}\n","import creator from \"../creator.js\";\n\nexport default function(name) {\n var create = typeof name === \"function\" ? name : creator(name);\n return this.select(function() {\n return this.appendChild(create.apply(this, arguments));\n });\n}\n","export default function(value) {\n return arguments.length\n ? this.property(\"__data__\", value)\n : this.node().__data__;\n}\n","export default function*() {\n for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {\n for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {\n if (node = group[i]) yield node;\n }\n }\n}\n","export default x => () => x;\n","import constant from \"./constant.js\";\n\nfunction linear(a, d) {\n return function(t) {\n return a + t * d;\n };\n}\n\nfunction exponential(a, b, y) {\n return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {\n return Math.pow(a + t * b, y);\n };\n}\n\nexport function hue(a, b) {\n var d = b - a;\n return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);\n}\n\nexport function gamma(y) {\n return (y = +y) === 1 ? nogamma : function(a, b) {\n return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);\n };\n}\n\nexport default function nogamma(a, b) {\n var d = b - a;\n return d ? linear(a, d) : constant(isNaN(a) ? b : a);\n}\n","import {rgb as colorRgb} from \"d3-color\";\nimport basis from \"./basis.js\";\nimport basisClosed from \"./basisClosed.js\";\nimport nogamma, {gamma} from \"./color.js\";\n\nexport default (function rgbGamma(y) {\n var color = gamma(y);\n\n function rgb(start, end) {\n var r = color((start = colorRgb(start)).r, (end = colorRgb(end)).r),\n g = color(start.g, end.g),\n b = color(start.b, end.b),\n opacity = nogamma(start.opacity, end.opacity);\n return function(t) {\n start.r = r(t);\n start.g = g(t);\n start.b = b(t);\n start.opacity = opacity(t);\n return start + \"\";\n };\n }\n\n rgb.gamma = rgbGamma;\n\n return rgb;\n})(1);\n\nfunction rgbSpline(spline) {\n return function(colors) {\n var n = colors.length,\n r = new Array(n),\n g = new Array(n),\n b = new Array(n),\n i, color;\n for (i = 0; i < n; ++i) {\n color = colorRgb(colors[i]);\n r[i] = color.r || 0;\n g[i] = color.g || 0;\n b[i] = color.b || 0;\n }\n r = spline(r);\n g = spline(g);\n b = spline(b);\n color.opacity = 1;\n return function(t) {\n color.r = r(t);\n color.g = g(t);\n color.b = b(t);\n return color + \"\";\n };\n };\n}\n\nexport var rgbBasis = rgbSpline(basis);\nexport var rgbBasisClosed = rgbSpline(basisClosed);\n","export default function(a, b) {\n if (!b) b = [];\n var n = a ? Math.min(b.length, a.length) : 0,\n c = b.slice(),\n i;\n return function(t) {\n for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;\n return c;\n };\n}\n\nexport function isNumberArray(x) {\n return ArrayBuffer.isView(x) && !(x instanceof DataView);\n}\n","import value from \"./value.js\";\nimport numberArray, {isNumberArray} from \"./numberArray.js\";\n\nexport default function(a, b) {\n return (isNumberArray(b) ? numberArray : genericArray)(a, b);\n}\n\nexport function genericArray(a, b) {\n var nb = b ? b.length : 0,\n na = a ? Math.min(nb, a.length) : 0,\n x = new Array(na),\n c = new Array(nb),\n i;\n\n for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);\n for (; i < nb; ++i) c[i] = b[i];\n\n return function(t) {\n for (i = 0; i < na; ++i) c[i] = x[i](t);\n return c;\n };\n}\n","export default function(a, b) {\n var d = new Date;\n return a = +a, b = +b, function(t) {\n return d.setTime(a * (1 - t) + b * t), d;\n };\n}\n","export default function(a, b) {\n return a = +a, b = +b, function(t) {\n return a * (1 - t) + b * t;\n };\n}\n","import value from \"./value.js\";\n\nexport default function(a, b) {\n var i = {},\n c = {},\n k;\n\n if (a === null || typeof a !== \"object\") a = {};\n if (b === null || typeof b !== \"object\") b = {};\n\n for (k in b) {\n if (k in a) {\n i[k] = value(a[k], b[k]);\n } else {\n c[k] = b[k];\n }\n }\n\n return function(t) {\n for (k in i) c[k] = i[k](t);\n return c;\n };\n}\n","import number from \"./number.js\";\n\nvar reA = /[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g,\n reB = new RegExp(reA.source, \"g\");\n\nfunction zero(b) {\n return function() {\n return b;\n };\n}\n\nfunction one(b) {\n return function(t) {\n return b(t) + \"\";\n };\n}\n\nexport default function(a, b) {\n var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b\n am, // current match in a\n bm, // current match in b\n bs, // string preceding current number in b, if any\n i = -1, // index in s\n s = [], // string constants and placeholders\n q = []; // number interpolators\n\n // Coerce inputs to strings.\n a = a + \"\", b = b + \"\";\n\n // Interpolate pairs of numbers in a & b.\n while ((am = reA.exec(a))\n && (bm = reB.exec(b))) {\n if ((bs = bm.index) > bi) { // a string precedes the next number in b\n bs = b.slice(bi, bs);\n if (s[i]) s[i] += bs; // coalesce with previous string\n else s[++i] = bs;\n }\n if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match\n if (s[i]) s[i] += bm; // coalesce with previous string\n else s[++i] = bm;\n } else { // interpolate non-matching numbers\n s[++i] = null;\n q.push({i: i, x: number(am, bm)});\n }\n bi = reB.lastIndex;\n }\n\n // Add remains of b.\n if (bi < b.length) {\n bs = b.slice(bi);\n if (s[i]) s[i] += bs; // coalesce with previous string\n else s[++i] = bs;\n }\n\n // Special optimization for only a single match.\n // Otherwise, interpolate each of the numbers and rejoin the string.\n return s.length < 2 ? (q[0]\n ? one(q[0].x)\n : zero(b))\n : (b = q.length, function(t) {\n for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);\n return s.join(\"\");\n });\n}\n","import {color} from \"d3-color\";\nimport rgb from \"./rgb.js\";\nimport {genericArray} from \"./array.js\";\nimport date from \"./date.js\";\nimport number from \"./number.js\";\nimport object from \"./object.js\";\nimport string from \"./string.js\";\nimport constant from \"./constant.js\";\nimport numberArray, {isNumberArray} from \"./numberArray.js\";\n\nexport default function(a, b) {\n var t = typeof b, c;\n return b == null || t === \"boolean\" ? constant(b)\n : (t === \"number\" ? number\n : t === \"string\" ? ((c = color(b)) ? (b = c, rgb) : string)\n : b instanceof color ? rgb\n : b instanceof Date ? date\n : isNumberArray(b) ? numberArray\n : Array.isArray(b) ? genericArray\n : typeof b.valueOf !== \"function\" && typeof b.toString !== \"function\" || isNaN(b) ? object\n : number)(a, b);\n}\n","export default function(a, b) {\n return a = +a, b = +b, function(t) {\n return Math.round(a * (1 - t) + b * t);\n };\n}\n","var degrees = 180 / Math.PI;\n\nexport var identity = {\n translateX: 0,\n translateY: 0,\n rotate: 0,\n skewX: 0,\n scaleX: 1,\n scaleY: 1\n};\n\nexport default function(a, b, c, d, e, f) {\n var scaleX, scaleY, skewX;\n if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;\n if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;\n if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;\n if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;\n return {\n translateX: e,\n translateY: f,\n rotate: Math.atan2(b, a) * degrees,\n skewX: Math.atan(skewX) * degrees,\n scaleX: scaleX,\n scaleY: scaleY\n };\n}\n","import decompose, {identity} from \"./decompose.js\";\n\nvar svgNode;\n\n/* eslint-disable no-undef */\nexport function parseCss(value) {\n const m = new (typeof DOMMatrix === \"function\" ? DOMMatrix : WebKitCSSMatrix)(value + \"\");\n return m.isIdentity ? identity : decompose(m.a, m.b, m.c, m.d, m.e, m.f);\n}\n\nexport function parseSvg(value) {\n if (value == null) return identity;\n if (!svgNode) svgNode = document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\");\n svgNode.setAttribute(\"transform\", value);\n if (!(value = svgNode.transform.baseVal.consolidate())) return identity;\n value = value.matrix;\n return decompose(value.a, value.b, value.c, value.d, value.e, value.f);\n}\n","import number from \"../number.js\";\nimport {parseCss, parseSvg} from \"./parse.js\";\n\nfunction interpolateTransform(parse, pxComma, pxParen, degParen) {\n\n function pop(s) {\n return s.length ? s.pop() + \" \" : \"\";\n }\n\n function translate(xa, ya, xb, yb, s, q) {\n if (xa !== xb || ya !== yb) {\n var i = s.push(\"translate(\", null, pxComma, null, pxParen);\n q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});\n } else if (xb || yb) {\n s.push(\"translate(\" + xb + pxComma + yb + pxParen);\n }\n }\n\n function rotate(a, b, s, q) {\n if (a !== b) {\n if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path\n q.push({i: s.push(pop(s) + \"rotate(\", null, degParen) - 2, x: number(a, b)});\n } else if (b) {\n s.push(pop(s) + \"rotate(\" + b + degParen);\n }\n }\n\n function skewX(a, b, s, q) {\n if (a !== b) {\n q.push({i: s.push(pop(s) + \"skewX(\", null, degParen) - 2, x: number(a, b)});\n } else if (b) {\n s.push(pop(s) + \"skewX(\" + b + degParen);\n }\n }\n\n function scale(xa, ya, xb, yb, s, q) {\n if (xa !== xb || ya !== yb) {\n var i = s.push(pop(s) + \"scale(\", null, \",\", null, \")\");\n q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});\n } else if (xb !== 1 || yb !== 1) {\n s.push(pop(s) + \"scale(\" + xb + \",\" + yb + \")\");\n }\n }\n\n return function(a, b) {\n var s = [], // string constants and placeholders\n q = []; // number interpolators\n a = parse(a), b = parse(b);\n translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);\n rotate(a.rotate, b.rotate, s, q);\n skewX(a.skewX, b.skewX, s, q);\n scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);\n a = b = null; // gc\n return function(t) {\n var i = -1, n = q.length, o;\n while (++i < n) s[(o = q[i]).i] = o.x(t);\n return s.join(\"\");\n };\n };\n}\n\nexport var interpolateTransformCss = interpolateTransform(parseCss, \"px, \", \"px)\", \"deg)\");\nexport var interpolateTransformSvg = interpolateTransform(parseSvg, \", \", \")\", \")\");\n","var frame = 0, // is an animation frame pending?\n timeout = 0, // is a timeout pending?\n interval = 0, // are any timers active?\n pokeDelay = 1000, // how frequently we check for clock skew\n taskHead,\n taskTail,\n clockLast = 0,\n clockNow = 0,\n clockSkew = 0,\n clock = typeof performance === \"object\" && performance.now ? performance : Date,\n setFrame = typeof window === \"object\" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); };\n\nexport function now() {\n return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);\n}\n\nfunction clearNow() {\n clockNow = 0;\n}\n\nexport function Timer() {\n this._call =\n this._time =\n this._next = null;\n}\n\nTimer.prototype = timer.prototype = {\n constructor: Timer,\n restart: function(callback, delay, time) {\n if (typeof callback !== \"function\") throw new TypeError(\"callback is not a function\");\n time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);\n if (!this._next && taskTail !== this) {\n if (taskTail) taskTail._next = this;\n else taskHead = this;\n taskTail = this;\n }\n this._call = callback;\n this._time = time;\n sleep();\n },\n stop: function() {\n if (this._call) {\n this._call = null;\n this._time = Infinity;\n sleep();\n }\n }\n};\n\nexport function timer(callback, delay, time) {\n var t = new Timer;\n t.restart(callback, delay, time);\n return t;\n}\n\nexport function timerFlush() {\n now(); // Get the current time, if not already set.\n ++frame; // Pretend we’ve set an alarm, if we haven’t already.\n var t = taskHead, e;\n while (t) {\n if ((e = clockNow - t._time) >= 0) t._call.call(undefined, e);\n t = t._next;\n }\n --frame;\n}\n\nfunction wake() {\n clockNow = (clockLast = clock.now()) + clockSkew;\n frame = timeout = 0;\n try {\n timerFlush();\n } finally {\n frame = 0;\n nap();\n clockNow = 0;\n }\n}\n\nfunction poke() {\n var now = clock.now(), delay = now - clockLast;\n if (delay > pokeDelay) clockSkew -= delay, clockLast = now;\n}\n\nfunction nap() {\n var t0, t1 = taskHead, t2, time = Infinity;\n while (t1) {\n if (t1._call) {\n if (time > t1._time) time = t1._time;\n t0 = t1, t1 = t1._next;\n } else {\n t2 = t1._next, t1._next = null;\n t1 = t0 ? t0._next = t2 : taskHead = t2;\n }\n }\n taskTail = t0;\n sleep(time);\n}\n\nfunction sleep(time) {\n if (frame) return; // Soonest alarm already set, or will be.\n if (timeout) timeout = clearTimeout(timeout);\n var delay = time - clockNow; // Strictly less than if we recomputed clockNow.\n if (delay > 24) {\n if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);\n if (interval) interval = clearInterval(interval);\n } else {\n if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);\n frame = 1, setFrame(wake);\n }\n}\n","import {Timer} from \"./timer.js\";\n\nexport default function(callback, delay, time) {\n var t = new Timer;\n delay = delay == null ? 0 : +delay;\n t.restart(elapsed => {\n t.stop();\n callback(elapsed + delay);\n }, delay, time);\n return t;\n}\n","import {dispatch} from \"d3-dispatch\";\nimport {timer, timeout} from \"d3-timer\";\n\nvar emptyOn = dispatch(\"start\", \"end\", \"cancel\", \"interrupt\");\nvar emptyTween = [];\n\nexport var CREATED = 0;\nexport var SCHEDULED = 1;\nexport var STARTING = 2;\nexport var STARTED = 3;\nexport var RUNNING = 4;\nexport var ENDING = 5;\nexport var ENDED = 6;\n\nexport default function(node, name, id, index, group, timing) {\n var schedules = node.__transition;\n if (!schedules) node.__transition = {};\n else if (id in schedules) return;\n create(node, id, {\n name: name,\n index: index, // For context during callback.\n group: group, // For context during callback.\n on: emptyOn,\n tween: emptyTween,\n time: timing.time,\n delay: timing.delay,\n duration: timing.duration,\n ease: timing.ease,\n timer: null,\n state: CREATED\n });\n}\n\nexport function init(node, id) {\n var schedule = get(node, id);\n if (schedule.state > CREATED) throw new Error(\"too late; already scheduled\");\n return schedule;\n}\n\nexport function set(node, id) {\n var schedule = get(node, id);\n if (schedule.state > STARTED) throw new Error(\"too late; already running\");\n return schedule;\n}\n\nexport function get(node, id) {\n var schedule = node.__transition;\n if (!schedule || !(schedule = schedule[id])) throw new Error(\"transition not found\");\n return schedule;\n}\n\nfunction create(node, id, self) {\n var schedules = node.__transition,\n tween;\n\n // Initialize the self timer when the transition is created.\n // Note the actual delay is not known until the first callback!\n schedules[id] = self;\n self.timer = timer(schedule, 0, self.time);\n\n function schedule(elapsed) {\n self.state = SCHEDULED;\n self.timer.restart(start, self.delay, self.time);\n\n // If the elapsed delay is less than our first sleep, start immediately.\n if (self.delay <= elapsed) start(elapsed - self.delay);\n }\n\n function start(elapsed) {\n var i, j, n, o;\n\n // If the state is not SCHEDULED, then we previously errored on start.\n if (self.state !== SCHEDULED) return stop();\n\n for (i in schedules) {\n o = schedules[i];\n if (o.name !== self.name) continue;\n\n // While this element already has a starting transition during this frame,\n // defer starting an interrupting transition until that transition has a\n // chance to tick (and possibly end); see d3/d3-transition#54!\n if (o.state === STARTED) return timeout(start);\n\n // Interrupt the active transition, if any.\n if (o.state === RUNNING) {\n o.state = ENDED;\n o.timer.stop();\n o.on.call(\"interrupt\", node, node.__data__, o.index, o.group);\n delete schedules[i];\n }\n\n // Cancel any pre-empted transitions.\n else if (+i < id) {\n o.state = ENDED;\n o.timer.stop();\n o.on.call(\"cancel\", node, node.__data__, o.index, o.group);\n delete schedules[i];\n }\n }\n\n // Defer the first tick to end of the current frame; see d3/d3#1576.\n // Note the transition may be canceled after start and before the first tick!\n // Note this must be scheduled before the start event; see d3/d3-transition#16!\n // Assuming this is successful, subsequent callbacks go straight to tick.\n timeout(function() {\n if (self.state === STARTED) {\n self.state = RUNNING;\n self.timer.restart(tick, self.delay, self.time);\n tick(elapsed);\n }\n });\n\n // Dispatch the start event.\n // Note this must be done before the tween are initialized.\n self.state = STARTING;\n self.on.call(\"start\", node, node.__data__, self.index, self.group);\n if (self.state !== STARTING) return; // interrupted\n self.state = STARTED;\n\n // Initialize the tween, deleting null tween.\n tween = new Array(n = self.tween.length);\n for (i = 0, j = -1; i < n; ++i) {\n if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {\n tween[++j] = o;\n }\n }\n tween.length = j + 1;\n }\n\n function tick(elapsed) {\n var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),\n i = -1,\n n = tween.length;\n\n while (++i < n) {\n tween[i].call(node, t);\n }\n\n // Dispatch the end event.\n if (self.state === ENDING) {\n self.on.call(\"end\", node, node.__data__, self.index, self.group);\n stop();\n }\n }\n\n function stop() {\n self.state = ENDED;\n self.timer.stop();\n delete schedules[id];\n for (var i in schedules) return; // eslint-disable-line no-unused-vars\n delete node.__transition;\n }\n}\n","import {get, set} from \"./schedule.js\";\n\nfunction tweenRemove(id, name) {\n var tween0, tween1;\n return function() {\n var schedule = set(this, id),\n tween = schedule.tween;\n\n // If this node shared tween with the previous node,\n // just assign the updated shared tween and we’re done!\n // Otherwise, copy-on-write.\n if (tween !== tween0) {\n tween1 = tween0 = tween;\n for (var i = 0, n = tween1.length; i < n; ++i) {\n if (tween1[i].name === name) {\n tween1 = tween1.slice();\n tween1.splice(i, 1);\n break;\n }\n }\n }\n\n schedule.tween = tween1;\n };\n}\n\nfunction tweenFunction(id, name, value) {\n var tween0, tween1;\n if (typeof value !== \"function\") throw new Error;\n return function() {\n var schedule = set(this, id),\n tween = schedule.tween;\n\n // If this node shared tween with the previous node,\n // just assign the updated shared tween and we’re done!\n // Otherwise, copy-on-write.\n if (tween !== tween0) {\n tween1 = (tween0 = tween).slice();\n for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {\n if (tween1[i].name === name) {\n tween1[i] = t;\n break;\n }\n }\n if (i === n) tween1.push(t);\n }\n\n schedule.tween = tween1;\n };\n}\n\nexport default function(name, value) {\n var id = this._id;\n\n name += \"\";\n\n if (arguments.length < 2) {\n var tween = get(this.node(), id).tween;\n for (var i = 0, n = tween.length, t; i < n; ++i) {\n if ((t = tween[i]).name === name) {\n return t.value;\n }\n }\n return null;\n }\n\n return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));\n}\n\nexport function tweenValue(transition, name, value) {\n var id = transition._id;\n\n transition.each(function() {\n var schedule = set(this, id);\n (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);\n });\n\n return function(node) {\n return get(node, id).value[name];\n };\n}\n","import {color} from \"d3-color\";\nimport {interpolateNumber, interpolateRgb, interpolateString} from \"d3-interpolate\";\n\nexport default function(a, b) {\n var c;\n return (typeof b === \"number\" ? interpolateNumber\n : b instanceof color ? interpolateRgb\n : (c = color(b)) ? (b = c, interpolateRgb)\n : interpolateString)(a, b);\n}\n","import {interpolateTransformSvg as interpolateTransform} from \"d3-interpolate\";\nimport {namespace} from \"d3-selection\";\nimport {tweenValue} from \"./tween.js\";\nimport interpolate from \"./interpolate.js\";\n\nfunction attrRemove(name) {\n return function() {\n this.removeAttribute(name);\n };\n}\n\nfunction attrRemoveNS(fullname) {\n return function() {\n this.removeAttributeNS(fullname.space, fullname.local);\n };\n}\n\nfunction attrConstant(name, interpolate, value1) {\n var string00,\n string1 = value1 + \"\",\n interpolate0;\n return function() {\n var string0 = this.getAttribute(name);\n return string0 === string1 ? null\n : string0 === string00 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, value1);\n };\n}\n\nfunction attrConstantNS(fullname, interpolate, value1) {\n var string00,\n string1 = value1 + \"\",\n interpolate0;\n return function() {\n var string0 = this.getAttributeNS(fullname.space, fullname.local);\n return string0 === string1 ? null\n : string0 === string00 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, value1);\n };\n}\n\nfunction attrFunction(name, interpolate, value) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0, value1 = value(this), string1;\n if (value1 == null) return void this.removeAttribute(name);\n string0 = this.getAttribute(name);\n string1 = value1 + \"\";\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n };\n}\n\nfunction attrFunctionNS(fullname, interpolate, value) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0, value1 = value(this), string1;\n if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);\n string0 = this.getAttributeNS(fullname.space, fullname.local);\n string1 = value1 + \"\";\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n };\n}\n\nexport default function(name, value) {\n var fullname = namespace(name), i = fullname === \"transform\" ? interpolateTransform : interpolate;\n return this.attrTween(name, typeof value === \"function\"\n ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, \"attr.\" + name, value))\n : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname)\n : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));\n}\n","import {namespace} from \"d3-selection\";\n\nfunction attrInterpolate(name, i) {\n return function(t) {\n this.setAttribute(name, i.call(this, t));\n };\n}\n\nfunction attrInterpolateNS(fullname, i) {\n return function(t) {\n this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));\n };\n}\n\nfunction attrTweenNS(fullname, value) {\n var t0, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);\n return t0;\n }\n tween._value = value;\n return tween;\n}\n\nfunction attrTween(name, value) {\n var t0, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);\n return t0;\n }\n tween._value = value;\n return tween;\n}\n\nexport default function(name, value) {\n var key = \"attr.\" + name;\n if (arguments.length < 2) return (key = this.tween(key)) && key._value;\n if (value == null) return this.tween(key, null);\n if (typeof value !== \"function\") throw new Error;\n var fullname = namespace(name);\n return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));\n}\n","import {get, init} from \"./schedule.js\";\n\nfunction delayFunction(id, value) {\n return function() {\n init(this, id).delay = +value.apply(this, arguments);\n };\n}\n\nfunction delayConstant(id, value) {\n return value = +value, function() {\n init(this, id).delay = value;\n };\n}\n\nexport default function(value) {\n var id = this._id;\n\n return arguments.length\n ? this.each((typeof value === \"function\"\n ? delayFunction\n : delayConstant)(id, value))\n : get(this.node(), id).delay;\n}\n","import {get, set} from \"./schedule.js\";\n\nfunction durationFunction(id, value) {\n return function() {\n set(this, id).duration = +value.apply(this, arguments);\n };\n}\n\nfunction durationConstant(id, value) {\n return value = +value, function() {\n set(this, id).duration = value;\n };\n}\n\nexport default function(value) {\n var id = this._id;\n\n return arguments.length\n ? this.each((typeof value === \"function\"\n ? durationFunction\n : durationConstant)(id, value))\n : get(this.node(), id).duration;\n}\n","import {selection} from \"d3-selection\";\n\nvar Selection = selection.prototype.constructor;\n\nexport default function() {\n return new Selection(this._groups, this._parents);\n}\n","import {interpolateTransformCss as interpolateTransform} from \"d3-interpolate\";\nimport {style} from \"d3-selection\";\nimport {set} from \"./schedule.js\";\nimport {tweenValue} from \"./tween.js\";\nimport interpolate from \"./interpolate.js\";\n\nfunction styleNull(name, interpolate) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0 = style(this, name),\n string1 = (this.style.removeProperty(name), style(this, name));\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, string10 = string1);\n };\n}\n\nfunction styleRemove(name) {\n return function() {\n this.style.removeProperty(name);\n };\n}\n\nfunction styleConstant(name, interpolate, value1) {\n var string00,\n string1 = value1 + \"\",\n interpolate0;\n return function() {\n var string0 = style(this, name);\n return string0 === string1 ? null\n : string0 === string00 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, value1);\n };\n}\n\nfunction styleFunction(name, interpolate, value) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0 = style(this, name),\n value1 = value(this),\n string1 = value1 + \"\";\n if (value1 == null) string1 = value1 = (this.style.removeProperty(name), style(this, name));\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n };\n}\n\nfunction styleMaybeRemove(id, name) {\n var on0, on1, listener0, key = \"style.\" + name, event = \"end.\" + key, remove;\n return function() {\n var schedule = set(this, id),\n on = schedule.on,\n listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined;\n\n // If this node shared a dispatch with the previous node,\n // just assign the updated shared dispatch and we’re done!\n // Otherwise, copy-on-write.\n if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);\n\n schedule.on = on1;\n };\n}\n\nexport default function(name, value, priority) {\n var i = (name += \"\") === \"transform\" ? interpolateTransform : interpolate;\n return value == null ? this\n .styleTween(name, styleNull(name, i))\n .on(\"end.style.\" + name, styleRemove(name))\n : typeof value === \"function\" ? this\n .styleTween(name, styleFunction(name, i, tweenValue(this, \"style.\" + name, value)))\n .each(styleMaybeRemove(this._id, name))\n : this\n .styleTween(name, styleConstant(name, i, value), priority)\n .on(\"end.style.\" + name, null);\n}\n","import {selection} from \"d3-selection\";\nimport transition_attr from \"./attr.js\";\nimport transition_attrTween from \"./attrTween.js\";\nimport transition_delay from \"./delay.js\";\nimport transition_duration from \"./duration.js\";\nimport transition_ease from \"./ease.js\";\nimport transition_easeVarying from \"./easeVarying.js\";\nimport transition_filter from \"./filter.js\";\nimport transition_merge from \"./merge.js\";\nimport transition_on from \"./on.js\";\nimport transition_remove from \"./remove.js\";\nimport transition_select from \"./select.js\";\nimport transition_selectAll from \"./selectAll.js\";\nimport transition_selection from \"./selection.js\";\nimport transition_style from \"./style.js\";\nimport transition_styleTween from \"./styleTween.js\";\nimport transition_text from \"./text.js\";\nimport transition_textTween from \"./textTween.js\";\nimport transition_transition from \"./transition.js\";\nimport transition_tween from \"./tween.js\";\nimport transition_end from \"./end.js\";\n\nvar id = 0;\n\nexport function Transition(groups, parents, name, id) {\n this._groups = groups;\n this._parents = parents;\n this._name = name;\n this._id = id;\n}\n\nexport default function transition(name) {\n return selection().transition(name);\n}\n\nexport function newId() {\n return ++id;\n}\n\nvar selection_prototype = selection.prototype;\n\nTransition.prototype = transition.prototype = {\n constructor: Transition,\n select: transition_select,\n selectAll: transition_selectAll,\n selectChild: selection_prototype.selectChild,\n selectChildren: selection_prototype.selectChildren,\n filter: transition_filter,\n merge: transition_merge,\n selection: transition_selection,\n transition: transition_transition,\n call: selection_prototype.call,\n nodes: selection_prototype.nodes,\n node: selection_prototype.node,\n size: selection_prototype.size,\n empty: selection_prototype.empty,\n each: selection_prototype.each,\n on: transition_on,\n attr: transition_attr,\n attrTween: transition_attrTween,\n style: transition_style,\n styleTween: transition_styleTween,\n text: transition_text,\n textTween: transition_textTween,\n remove: transition_remove,\n tween: transition_tween,\n delay: transition_delay,\n duration: transition_duration,\n ease: transition_ease,\n easeVarying: transition_easeVarying,\n end: transition_end,\n [Symbol.iterator]: selection_prototype[Symbol.iterator]\n};\n","import {selector} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function(select) {\n var name = this._name,\n id = this._id;\n\n if (typeof select !== \"function\") select = selector(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {\n if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {\n if (\"__data__\" in node) subnode.__data__ = node.__data__;\n subgroup[i] = subnode;\n schedule(subgroup[i], name, id, i, subgroup, get(node, id));\n }\n }\n }\n\n return new Transition(subgroups, this._parents, name, id);\n}\n","import {selectorAll} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function(select) {\n var name = this._name,\n id = this._id;\n\n if (typeof select !== \"function\") select = selectorAll(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) {\n if (child = children[k]) {\n schedule(child, name, id, k, children, inherit);\n }\n }\n subgroups.push(children);\n parents.push(node);\n }\n }\n }\n\n return new Transition(subgroups, parents, name, id);\n}\n","import {matcher} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\n\nexport default function(match) {\n if (typeof match !== \"function\") match = matcher(match);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {\n if ((node = group[i]) && match.call(node, node.__data__, i, group)) {\n subgroup.push(node);\n }\n }\n }\n\n return new Transition(subgroups, this._parents, this._name, this._id);\n}\n","import {Transition} from \"./index.js\";\n\nexport default function(transition) {\n if (transition._id !== this._id) throw new Error;\n\n for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {\n for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {\n if (node = group0[i] || group1[i]) {\n merge[i] = node;\n }\n }\n }\n\n for (; j < m0; ++j) {\n merges[j] = groups0[j];\n }\n\n return new Transition(merges, this._parents, this._name, this._id);\n}\n","import {Transition, newId} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function() {\n var name = this._name,\n id0 = this._id,\n id1 = newId();\n\n for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n var inherit = get(node, id0);\n schedule(node, name, id1, i, group, {\n time: inherit.time + inherit.delay + inherit.duration,\n delay: 0,\n duration: inherit.duration,\n ease: inherit.ease\n });\n }\n }\n }\n\n return new Transition(groups, this._parents, name, id1);\n}\n","import {get, set, init} from \"./schedule.js\";\n\nfunction start(name) {\n return (name + \"\").trim().split(/^|\\s+/).every(function(t) {\n var i = t.indexOf(\".\");\n if (i >= 0) t = t.slice(0, i);\n return !t || t === \"start\";\n });\n}\n\nfunction onFunction(id, name, listener) {\n var on0, on1, sit = start(name) ? init : set;\n return function() {\n var schedule = sit(this, id),\n on = schedule.on;\n\n // If this node shared a dispatch with the previous node,\n // just assign the updated shared dispatch and we’re done!\n // Otherwise, copy-on-write.\n if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);\n\n schedule.on = on1;\n };\n}\n\nexport default function(name, listener) {\n var id = this._id;\n\n return arguments.length < 2\n ? get(this.node(), id).on.on(name)\n : this.each(onFunction(id, name, listener));\n}\n","function styleInterpolate(name, i, priority) {\n return function(t) {\n this.style.setProperty(name, i.call(this, t), priority);\n };\n}\n\nfunction styleTween(name, value, priority) {\n var t, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);\n return t;\n }\n tween._value = value;\n return tween;\n}\n\nexport default function(name, value, priority) {\n var key = \"style.\" + (name += \"\");\n if (arguments.length < 2) return (key = this.tween(key)) && key._value;\n if (value == null) return this.tween(key, null);\n if (typeof value !== \"function\") throw new Error;\n return this.tween(key, styleTween(name, value, priority == null ? \"\" : priority));\n}\n","import {tweenValue} from \"./tween.js\";\n\nfunction textConstant(value) {\n return function() {\n this.textContent = value;\n };\n}\n\nfunction textFunction(value) {\n return function() {\n var value1 = value(this);\n this.textContent = value1 == null ? \"\" : value1;\n };\n}\n\nexport default function(value) {\n return this.tween(\"text\", typeof value === \"function\"\n ? textFunction(tweenValue(this, \"text\", value))\n : textConstant(value == null ? \"\" : value + \"\"));\n}\n","function textInterpolate(i) {\n return function(t) {\n this.textContent = i.call(this, t);\n };\n}\n\nfunction textTween(value) {\n var t0, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t0 = (i0 = i) && textInterpolate(i);\n return t0;\n }\n tween._value = value;\n return tween;\n}\n\nexport default function(value) {\n var key = \"text\";\n if (arguments.length < 1) return (key = this.tween(key)) && key._value;\n if (value == null) return this.tween(key, null);\n if (typeof value !== \"function\") throw new Error;\n return this.tween(key, textTween(value));\n}\n","function removeFunction(id) {\n return function() {\n var parent = this.parentNode;\n for (var i in this.__transition) if (+i !== id) return;\n if (parent) parent.removeChild(this);\n };\n}\n\nexport default function() {\n return this.on(\"end.remove\", removeFunction(this._id));\n}\n","import {get, set} from \"./schedule.js\";\n\nfunction easeConstant(id, value) {\n if (typeof value !== \"function\") throw new Error;\n return function() {\n set(this, id).ease = value;\n };\n}\n\nexport default function(value) {\n var id = this._id;\n\n return arguments.length\n ? this.each(easeConstant(id, value))\n : get(this.node(), id).ease;\n}\n","import {set} from \"./schedule.js\";\n\nfunction easeVarying(id, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (typeof v !== \"function\") throw new Error;\n set(this, id).ease = v;\n };\n}\n\nexport default function(value) {\n if (typeof value !== \"function\") throw new Error;\n return this.each(easeVarying(this._id, value));\n}\n","import {set} from \"./schedule.js\";\n\nexport default function() {\n var on0, on1, that = this, id = that._id, size = that.size();\n return new Promise(function(resolve, reject) {\n var cancel = {value: reject},\n end = {value: function() { if (--size === 0) resolve(); }};\n\n that.each(function() {\n var schedule = set(this, id),\n on = schedule.on;\n\n // If this node shared a dispatch with the previous node,\n // just assign the updated shared dispatch and we’re done!\n // Otherwise, copy-on-write.\n if (on !== on0) {\n on1 = (on0 = on).copy();\n on1._.cancel.push(cancel);\n on1._.interrupt.push(cancel);\n on1._.end.push(end);\n }\n\n schedule.on = on1;\n });\n\n // The selection was empty, resolve end immediately\n if (size === 0) resolve();\n });\n}\n","import {Transition, newId} from \"../transition/index.js\";\nimport schedule from \"../transition/schedule.js\";\nimport {easeCubicInOut} from \"d3-ease\";\nimport {now} from \"d3-timer\";\n\nvar defaultTiming = {\n time: null, // Set on use.\n delay: 0,\n duration: 250,\n ease: easeCubicInOut\n};\n\nfunction inherit(node, id) {\n var timing;\n while (!(timing = node.__transition) || !(timing = timing[id])) {\n if (!(node = node.parentNode)) {\n throw new Error(`transition ${id} not found`);\n }\n }\n return timing;\n}\n\nexport default function(name) {\n var id,\n timing;\n\n if (name instanceof Transition) {\n id = name._id, name = name._name;\n } else {\n id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + \"\";\n }\n\n for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n schedule(node, name, id, i, group, timing || inherit(node, id));\n }\n }\n }\n\n return new Transition(groups, this._parents, name, id);\n}\n","export function cubicIn(t) {\n return t * t * t;\n}\n\nexport function cubicOut(t) {\n return --t * t * t + 1;\n}\n\nexport function cubicInOut(t) {\n return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;\n}\n","import {selection} from \"d3-selection\";\nimport selection_interrupt from \"./interrupt.js\";\nimport selection_transition from \"./transition.js\";\n\nselection.prototype.interrupt = selection_interrupt;\nselection.prototype.transition = selection_transition;\n","import interrupt from \"../interrupt.js\";\n\nexport default function(name) {\n return this.each(function() {\n interrupt(this, name);\n });\n}\n","import {STARTING, ENDING, ENDED} from \"./transition/schedule.js\";\n\nexport default function(node, name) {\n var schedules = node.__transition,\n schedule,\n active,\n empty = true,\n i;\n\n if (!schedules) return;\n\n name = name == null ? null : name + \"\";\n\n for (i in schedules) {\n if ((schedule = schedules[i]).name !== name) { empty = false; continue; }\n active = schedule.state > STARTING && schedule.state < ENDING;\n schedule.state = ENDED;\n schedule.timer.stop();\n schedule.on.call(active ? \"interrupt\" : \"cancel\", node, node.__data__, schedule.index, schedule.group);\n delete schedules[i];\n }\n\n if (empty) delete node.__transition;\n}\n","const pi = Math.PI,\n tau = 2 * pi,\n epsilon = 1e-6,\n tauEpsilon = tau - epsilon;\n\nfunction append(strings) {\n this._ += strings[0];\n for (let i = 1, n = strings.length; i < n; ++i) {\n this._ += arguments[i] + strings[i];\n }\n}\n\nfunction appendRound(digits) {\n let d = Math.floor(digits);\n if (!(d >= 0)) throw new Error(`invalid digits: ${digits}`);\n if (d > 15) return append;\n const k = 10 ** d;\n return function(strings) {\n this._ += strings[0];\n for (let i = 1, n = strings.length; i < n; ++i) {\n this._ += Math.round(arguments[i] * k) / k + strings[i];\n }\n };\n}\n\nexport class Path {\n constructor(digits) {\n this._x0 = this._y0 = // start of current subpath\n this._x1 = this._y1 = null; // end of current subpath\n this._ = \"\";\n this._append = digits == null ? append : appendRound(digits);\n }\n moveTo(x, y) {\n this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`;\n }\n closePath() {\n if (this._x1 !== null) {\n this._x1 = this._x0, this._y1 = this._y0;\n this._append`Z`;\n }\n }\n lineTo(x, y) {\n this._append`L${this._x1 = +x},${this._y1 = +y}`;\n }\n quadraticCurveTo(x1, y1, x, y) {\n this._append`Q${+x1},${+y1},${this._x1 = +x},${this._y1 = +y}`;\n }\n bezierCurveTo(x1, y1, x2, y2, x, y) {\n this._append`C${+x1},${+y1},${+x2},${+y2},${this._x1 = +x},${this._y1 = +y}`;\n }\n arcTo(x1, y1, x2, y2, r) {\n x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(`negative radius: ${r}`);\n\n let x0 = this._x1,\n y0 = this._y1,\n x21 = x2 - x1,\n y21 = y2 - y1,\n x01 = x0 - x1,\n y01 = y0 - y1,\n l01_2 = x01 * x01 + y01 * y01;\n\n // Is this path empty? Move to (x1,y1).\n if (this._x1 === null) {\n this._append`M${this._x1 = x1},${this._y1 = y1}`;\n }\n\n // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.\n else if (!(l01_2 > epsilon));\n\n // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?\n // Equivalently, is (x1,y1) coincident with (x2,y2)?\n // Or, is the radius zero? Line to (x1,y1).\n else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {\n this._append`L${this._x1 = x1},${this._y1 = y1}`;\n }\n\n // Otherwise, draw an arc!\n else {\n let x20 = x2 - x0,\n y20 = y2 - y0,\n l21_2 = x21 * x21 + y21 * y21,\n l20_2 = x20 * x20 + y20 * y20,\n l21 = Math.sqrt(l21_2),\n l01 = Math.sqrt(l01_2),\n l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),\n t01 = l / l01,\n t21 = l / l21;\n\n // If the start tangent is not coincident with (x0,y0), line to.\n if (Math.abs(t01 - 1) > epsilon) {\n this._append`L${x1 + t01 * x01},${y1 + t01 * y01}`;\n }\n\n this._append`A${r},${r},0,0,${+(y01 * x20 > x01 * y20)},${this._x1 = x1 + t21 * x21},${this._y1 = y1 + t21 * y21}`;\n }\n }\n arc(x, y, r, a0, a1, ccw) {\n x = +x, y = +y, r = +r, ccw = !!ccw;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(`negative radius: ${r}`);\n\n let dx = r * Math.cos(a0),\n dy = r * Math.sin(a0),\n x0 = x + dx,\n y0 = y + dy,\n cw = 1 ^ ccw,\n da = ccw ? a0 - a1 : a1 - a0;\n\n // Is this path empty? Move to (x0,y0).\n if (this._x1 === null) {\n this._append`M${x0},${y0}`;\n }\n\n // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).\n else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {\n this._append`L${x0},${y0}`;\n }\n\n // Is this arc empty? We’re done.\n if (!r) return;\n\n // Does the angle go the wrong way? Flip the direction.\n if (da < 0) da = da % tau + tau;\n\n // Is this a complete circle? Draw two arcs to complete the circle.\n if (da > tauEpsilon) {\n this._append`A${r},${r},0,1,${cw},${x - dx},${y - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;\n }\n\n // Is this arc non-empty? Draw an arc!\n else if (da > epsilon) {\n this._append`A${r},${r},0,${+(da >= pi)},${cw},${this._x1 = x + r * Math.cos(a1)},${this._y1 = y + r * Math.sin(a1)}`;\n }\n }\n rect(x, y, w, h) {\n this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${w = +w}v${+h}h${-w}Z`;\n }\n toString() {\n return this._;\n }\n}\n\nexport function path() {\n return new Path;\n}\n\n// Allow instanceof d3.path\npath.prototype = Path.prototype;\n\nexport function pathRound(digits = 3) {\n return new Path(+digits);\n}\n","export default function(x) {\n return Math.abs(x = Math.round(x)) >= 1e21\n ? x.toLocaleString(\"en\").replace(/,/g, \"\")\n : x.toString(10);\n}\n\n// Computes the decimal coefficient and exponent of the specified number x with\n// significant digits p, where x is positive and p is in [1, 21] or undefined.\n// For example, formatDecimalParts(1.23) returns [\"123\", 0].\nexport function formatDecimalParts(x, p) {\n if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf(\"e\")) < 0) return null; // NaN, Β±Infinity\n var i, coefficient = x.slice(0, i);\n\n // The string returned by toExponential either has the form \\d\\.\\d+e[-+]\\d+\n // (e.g., 1.2e+3) or the form \\de[-+]\\d+ (e.g., 1e+3).\n return [\n coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,\n +x.slice(i + 1)\n ];\n}\n","import {formatDecimalParts} from \"./formatDecimal.js\";\n\nexport default function(x) {\n return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;\n}\n","// [[fill]align][sign][symbol][0][width][,][.precision][~][type]\nvar re = /^(?:(.)?([<>=^]))?([+\\-( ])?([$#])?(0)?(\\d+)?(,)?(\\.\\d+)?(~)?([a-z%])?$/i;\n\nexport default function formatSpecifier(specifier) {\n if (!(match = re.exec(specifier))) throw new Error(\"invalid format: \" + specifier);\n var match;\n return new FormatSpecifier({\n fill: match[1],\n align: match[2],\n sign: match[3],\n symbol: match[4],\n zero: match[5],\n width: match[6],\n comma: match[7],\n precision: match[8] && match[8].slice(1),\n trim: match[9],\n type: match[10]\n });\n}\n\nformatSpecifier.prototype = FormatSpecifier.prototype; // instanceof\n\nexport function FormatSpecifier(specifier) {\n this.fill = specifier.fill === undefined ? \" \" : specifier.fill + \"\";\n this.align = specifier.align === undefined ? \">\" : specifier.align + \"\";\n this.sign = specifier.sign === undefined ? \"-\" : specifier.sign + \"\";\n this.symbol = specifier.symbol === undefined ? \"\" : specifier.symbol + \"\";\n this.zero = !!specifier.zero;\n this.width = specifier.width === undefined ? undefined : +specifier.width;\n this.comma = !!specifier.comma;\n this.precision = specifier.precision === undefined ? undefined : +specifier.precision;\n this.trim = !!specifier.trim;\n this.type = specifier.type === undefined ? \"\" : specifier.type + \"\";\n}\n\nFormatSpecifier.prototype.toString = function() {\n return this.fill\n + this.align\n + this.sign\n + this.symbol\n + (this.zero ? \"0\" : \"\")\n + (this.width === undefined ? \"\" : Math.max(1, this.width | 0))\n + (this.comma ? \",\" : \"\")\n + (this.precision === undefined ? \"\" : \".\" + Math.max(0, this.precision | 0))\n + (this.trim ? \"~\" : \"\")\n + this.type;\n};\n","import {formatDecimalParts} from \"./formatDecimal.js\";\n\nexport var prefixExponent;\n\nexport default function(x, p) {\n var d = formatDecimalParts(x, p);\n if (!d) return x + \"\";\n var coefficient = d[0],\n exponent = d[1],\n i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,\n n = coefficient.length;\n return i === n ? coefficient\n : i > n ? coefficient + new Array(i - n + 1).join(\"0\")\n : i > 0 ? coefficient.slice(0, i) + \".\" + coefficient.slice(i)\n : \"0.\" + new Array(1 - i).join(\"0\") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!\n}\n","import {formatDecimalParts} from \"./formatDecimal.js\";\n\nexport default function(x, p) {\n var d = formatDecimalParts(x, p);\n if (!d) return x + \"\";\n var coefficient = d[0],\n exponent = d[1];\n return exponent < 0 ? \"0.\" + new Array(-exponent).join(\"0\") + coefficient\n : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + \".\" + coefficient.slice(exponent + 1)\n : coefficient + new Array(exponent - coefficient.length + 2).join(\"0\");\n}\n","import formatDecimal from \"./formatDecimal.js\";\nimport formatPrefixAuto from \"./formatPrefixAuto.js\";\nimport formatRounded from \"./formatRounded.js\";\n\nexport default {\n \"%\": (x, p) => (x * 100).toFixed(p),\n \"b\": (x) => Math.round(x).toString(2),\n \"c\": (x) => x + \"\",\n \"d\": formatDecimal,\n \"e\": (x, p) => x.toExponential(p),\n \"f\": (x, p) => x.toFixed(p),\n \"g\": (x, p) => x.toPrecision(p),\n \"o\": (x) => Math.round(x).toString(8),\n \"p\": (x, p) => formatRounded(x * 100, p),\n \"r\": formatRounded,\n \"s\": formatPrefixAuto,\n \"X\": (x) => Math.round(x).toString(16).toUpperCase(),\n \"x\": (x) => Math.round(x).toString(16)\n};\n","export default function(x) {\n return x;\n}\n","import exponent from \"./exponent.js\";\nimport formatGroup from \"./formatGroup.js\";\nimport formatNumerals from \"./formatNumerals.js\";\nimport formatSpecifier from \"./formatSpecifier.js\";\nimport formatTrim from \"./formatTrim.js\";\nimport formatTypes from \"./formatTypes.js\";\nimport {prefixExponent} from \"./formatPrefixAuto.js\";\nimport identity from \"./identity.js\";\n\nvar map = Array.prototype.map,\n prefixes = [\"y\",\"z\",\"a\",\"f\",\"p\",\"n\",\"Β΅\",\"m\",\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\",\"Y\"];\n\nexport default function(locale) {\n var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map.call(locale.grouping, Number), locale.thousands + \"\"),\n currencyPrefix = locale.currency === undefined ? \"\" : locale.currency[0] + \"\",\n currencySuffix = locale.currency === undefined ? \"\" : locale.currency[1] + \"\",\n decimal = locale.decimal === undefined ? \".\" : locale.decimal + \"\",\n numerals = locale.numerals === undefined ? identity : formatNumerals(map.call(locale.numerals, String)),\n percent = locale.percent === undefined ? \"%\" : locale.percent + \"\",\n minus = locale.minus === undefined ? \"βˆ’\" : locale.minus + \"\",\n nan = locale.nan === undefined ? \"NaN\" : locale.nan + \"\";\n\n function newFormat(specifier) {\n specifier = formatSpecifier(specifier);\n\n var fill = specifier.fill,\n align = specifier.align,\n sign = specifier.sign,\n symbol = specifier.symbol,\n zero = specifier.zero,\n width = specifier.width,\n comma = specifier.comma,\n precision = specifier.precision,\n trim = specifier.trim,\n type = specifier.type;\n\n // The \"n\" type is an alias for \",g\".\n if (type === \"n\") comma = true, type = \"g\";\n\n // The \"\" type, and any invalid type, is an alias for \".12~g\".\n else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = \"g\";\n\n // If zero fill is specified, padding goes after sign and before digits.\n if (zero || (fill === \"0\" && align === \"=\")) zero = true, fill = \"0\", align = \"=\";\n\n // Compute the prefix and suffix.\n // For SI-prefix, the suffix is lazily computed.\n var prefix = symbol === \"$\" ? currencyPrefix : symbol === \"#\" && /[boxX]/.test(type) ? \"0\" + type.toLowerCase() : \"\",\n suffix = symbol === \"$\" ? currencySuffix : /[%p]/.test(type) ? percent : \"\";\n\n // What format function should we use?\n // Is this an integer type?\n // Can this type generate exponential notation?\n var formatType = formatTypes[type],\n maybeSuffix = /[defgprs%]/.test(type);\n\n // Set the default precision if not specified,\n // or clamp the specified precision to the supported range.\n // For significant precision, it must be in [1, 21].\n // For fixed precision, it must be in [0, 20].\n precision = precision === undefined ? 6\n : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))\n : Math.max(0, Math.min(20, precision));\n\n function format(value) {\n var valuePrefix = prefix,\n valueSuffix = suffix,\n i, n, c;\n\n if (type === \"c\") {\n valueSuffix = formatType(value) + valueSuffix;\n value = \"\";\n } else {\n value = +value;\n\n // Determine the sign. -0 is not less than 0, but 1 / -0 is!\n var valueNegative = value < 0 || 1 / value < 0;\n\n // Perform the initial formatting.\n value = isNaN(value) ? nan : formatType(Math.abs(value), precision);\n\n // Trim insignificant zeros.\n if (trim) value = formatTrim(value);\n\n // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.\n if (valueNegative && +value === 0 && sign !== \"+\") valueNegative = false;\n\n // Compute the prefix and suffix.\n valuePrefix = (valueNegative ? (sign === \"(\" ? sign : minus) : sign === \"-\" || sign === \"(\" ? \"\" : sign) + valuePrefix;\n valueSuffix = (type === \"s\" ? prefixes[8 + prefixExponent / 3] : \"\") + valueSuffix + (valueNegative && sign === \"(\" ? \")\" : \"\");\n\n // Break the formatted value into the integer β€œvalue” part that can be\n // grouped, and fractional or exponential β€œsuffix” part that is not.\n if (maybeSuffix) {\n i = -1, n = value.length;\n while (++i < n) {\n if (c = value.charCodeAt(i), 48 > c || c > 57) {\n valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;\n value = value.slice(0, i);\n break;\n }\n }\n }\n }\n\n // If the fill character is not \"0\", grouping is applied before padding.\n if (comma && !zero) value = group(value, Infinity);\n\n // Compute the padding.\n var length = valuePrefix.length + value.length + valueSuffix.length,\n padding = length < width ? new Array(width - length + 1).join(fill) : \"\";\n\n // If the fill character is \"0\", grouping is applied after padding.\n if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = \"\";\n\n // Reconstruct the final output based on the desired alignment.\n switch (align) {\n case \"<\": value = valuePrefix + value + valueSuffix + padding; break;\n case \"=\": value = valuePrefix + padding + value + valueSuffix; break;\n case \"^\": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;\n default: value = padding + valuePrefix + value + valueSuffix; break;\n }\n\n return numerals(value);\n }\n\n format.toString = function() {\n return specifier + \"\";\n };\n\n return format;\n }\n\n function formatPrefix(specifier, value) {\n var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = \"f\", specifier)),\n e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,\n k = Math.pow(10, -e),\n prefix = prefixes[8 + e / 3];\n return function(value) {\n return f(k * value) + prefix;\n };\n }\n\n return {\n format: newFormat,\n formatPrefix: formatPrefix\n };\n}\n","import formatLocale from \"./locale.js\";\n\nvar locale;\nexport var format;\nexport var formatPrefix;\n\ndefaultLocale({\n thousands: \",\",\n grouping: [3],\n currency: [\"$\", \"\"]\n});\n\nexport default function defaultLocale(definition) {\n locale = formatLocale(definition);\n format = locale.format;\n formatPrefix = locale.formatPrefix;\n return locale;\n}\n","export default function(grouping, thousands) {\n return function(value, width) {\n var i = value.length,\n t = [],\n j = 0,\n g = grouping[0],\n length = 0;\n\n while (i > 0 && g > 0) {\n if (length + g + 1 > width) g = Math.max(1, width - length);\n t.push(value.substring(i -= g, i + g));\n if ((length += g + 1) > width) break;\n g = grouping[j = (j + 1) % grouping.length];\n }\n\n return t.reverse().join(thousands);\n };\n}\n","export default function(numerals) {\n return function(value) {\n return value.replace(/[0-9]/g, function(i) {\n return numerals[+i];\n });\n };\n}\n","// Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.\nexport default function(s) {\n out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {\n switch (s[i]) {\n case \".\": i0 = i1 = i; break;\n case \"0\": if (i0 === 0) i0 = i; i1 = i; break;\n default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break;\n }\n }\n return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;\n}\n","export function initRange(domain, range) {\n switch (arguments.length) {\n case 0: break;\n case 1: this.range(domain); break;\n default: this.range(range).domain(domain); break;\n }\n return this;\n}\n\nexport function initInterpolator(domain, interpolator) {\n switch (arguments.length) {\n case 0: break;\n case 1: {\n if (typeof domain === \"function\") this.interpolator(domain);\n else this.range(domain);\n break;\n }\n default: {\n this.domain(domain);\n if (typeof interpolator === \"function\") this.interpolator(interpolator);\n else this.range(interpolator);\n break;\n }\n }\n return this;\n}\n","export default function number(x) {\n return +x;\n}\n","import {bisect} from \"d3-array\";\nimport {interpolate as interpolateValue, interpolateNumber, interpolateRound} from \"d3-interpolate\";\nimport constant from \"./constant.js\";\nimport number from \"./number.js\";\n\nvar unit = [0, 1];\n\nexport function identity(x) {\n return x;\n}\n\nfunction normalize(a, b) {\n return (b -= (a = +a))\n ? function(x) { return (x - a) / b; }\n : constant(isNaN(b) ? NaN : 0.5);\n}\n\nfunction clamper(a, b) {\n var t;\n if (a > b) t = a, a = b, b = t;\n return function(x) { return Math.max(a, Math.min(b, x)); };\n}\n\n// normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].\n// interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].\nfunction bimap(domain, range, interpolate) {\n var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];\n if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);\n else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);\n return function(x) { return r0(d0(x)); };\n}\n\nfunction polymap(domain, range, interpolate) {\n var j = Math.min(domain.length, range.length) - 1,\n d = new Array(j),\n r = new Array(j),\n i = -1;\n\n // Reverse descending domains.\n if (domain[j] < domain[0]) {\n domain = domain.slice().reverse();\n range = range.slice().reverse();\n }\n\n while (++i < j) {\n d[i] = normalize(domain[i], domain[i + 1]);\n r[i] = interpolate(range[i], range[i + 1]);\n }\n\n return function(x) {\n var i = bisect(domain, x, 1, j) - 1;\n return r[i](d[i](x));\n };\n}\n\nexport function copy(source, target) {\n return target\n .domain(source.domain())\n .range(source.range())\n .interpolate(source.interpolate())\n .clamp(source.clamp())\n .unknown(source.unknown());\n}\n\nexport function transformer() {\n var domain = unit,\n range = unit,\n interpolate = interpolateValue,\n transform,\n untransform,\n unknown,\n clamp = identity,\n piecewise,\n output,\n input;\n\n function rescale() {\n var n = Math.min(domain.length, range.length);\n if (clamp !== identity) clamp = clamper(domain[0], domain[n - 1]);\n piecewise = n > 2 ? polymap : bimap;\n output = input = null;\n return scale;\n }\n\n function scale(x) {\n return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));\n }\n\n scale.invert = function(y) {\n return clamp(untransform((input || (input = piecewise(range, domain.map(transform), interpolateNumber)))(y)));\n };\n\n scale.domain = function(_) {\n return arguments.length ? (domain = Array.from(_, number), rescale()) : domain.slice();\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = Array.from(_), rescale()) : range.slice();\n };\n\n scale.rangeRound = function(_) {\n return range = Array.from(_), interpolate = interpolateRound, rescale();\n };\n\n scale.clamp = function(_) {\n return arguments.length ? (clamp = _ ? true : identity, rescale()) : clamp !== identity;\n };\n\n scale.interpolate = function(_) {\n return arguments.length ? (interpolate = _, rescale()) : interpolate;\n };\n\n scale.unknown = function(_) {\n return arguments.length ? (unknown = _, scale) : unknown;\n };\n\n return function(t, u) {\n transform = t, untransform = u;\n return rescale();\n };\n}\n\nexport default function continuous() {\n return transformer()(identity, identity);\n}\n","export default function constants(x) {\n return function() {\n return x;\n };\n}\n","import {tickStep} from \"d3-array\";\nimport {format, formatPrefix, formatSpecifier, precisionFixed, precisionPrefix, precisionRound} from \"d3-format\";\n\nexport default function tickFormat(start, stop, count, specifier) {\n var step = tickStep(start, stop, count),\n precision;\n specifier = formatSpecifier(specifier == null ? \",f\" : specifier);\n switch (specifier.type) {\n case \"s\": {\n var value = Math.max(Math.abs(start), Math.abs(stop));\n if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;\n return formatPrefix(specifier, value);\n }\n case \"\":\n case \"e\":\n case \"g\":\n case \"p\":\n case \"r\": {\n if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === \"e\");\n break;\n }\n case \"f\":\n case \"%\": {\n if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === \"%\") * 2;\n break;\n }\n }\n return format(specifier);\n}\n","import exponent from \"./exponent.js\";\n\nexport default function(step, value) {\n return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));\n}\n","import exponent from \"./exponent.js\";\n\nexport default function(step, max) {\n step = Math.abs(step), max = Math.abs(max) - step;\n return Math.max(0, exponent(max) - exponent(step)) + 1;\n}\n","import exponent from \"./exponent.js\";\n\nexport default function(step) {\n return Math.max(0, -exponent(Math.abs(step)));\n}\n","import {ticks, tickIncrement} from \"d3-array\";\nimport continuous, {copy} from \"./continuous.js\";\nimport {initRange} from \"./init.js\";\nimport tickFormat from \"./tickFormat.js\";\n\nexport function linearish(scale) {\n var domain = scale.domain;\n\n scale.ticks = function(count) {\n var d = domain();\n return ticks(d[0], d[d.length - 1], count == null ? 10 : count);\n };\n\n scale.tickFormat = function(count, specifier) {\n var d = domain();\n return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);\n };\n\n scale.nice = function(count) {\n if (count == null) count = 10;\n\n var d = domain();\n var i0 = 0;\n var i1 = d.length - 1;\n var start = d[i0];\n var stop = d[i1];\n var prestep;\n var step;\n var maxIter = 10;\n\n if (stop < start) {\n step = start, start = stop, stop = step;\n step = i0, i0 = i1, i1 = step;\n }\n \n while (maxIter-- > 0) {\n step = tickIncrement(start, stop, count);\n if (step === prestep) {\n d[i0] = start\n d[i1] = stop\n return domain(d);\n } else if (step > 0) {\n start = Math.floor(start / step) * step;\n stop = Math.ceil(stop / step) * step;\n } else if (step < 0) {\n start = Math.ceil(start * step) / step;\n stop = Math.floor(stop * step) / step;\n } else {\n break;\n }\n prestep = step;\n }\n\n return scale;\n };\n\n return scale;\n}\n\nexport default function linear() {\n var scale = continuous();\n\n scale.copy = function() {\n return copy(scale, linear());\n };\n\n initRange.apply(scale, arguments);\n\n return linearish(scale);\n}\n","const t0 = new Date, t1 = new Date;\n\nexport function timeInterval(floori, offseti, count, field) {\n\n function interval(date) {\n return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date;\n }\n\n interval.floor = (date) => {\n return floori(date = new Date(+date)), date;\n };\n\n interval.ceil = (date) => {\n return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;\n };\n\n interval.round = (date) => {\n const d0 = interval(date), d1 = interval.ceil(date);\n return date - d0 < d1 - date ? d0 : d1;\n };\n\n interval.offset = (date, step) => {\n return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;\n };\n\n interval.range = (start, stop, step) => {\n const range = [];\n start = interval.ceil(start);\n step = step == null ? 1 : Math.floor(step);\n if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date\n let previous;\n do range.push(previous = new Date(+start)), offseti(start, step), floori(start);\n while (previous < start && start < stop);\n return range;\n };\n\n interval.filter = (test) => {\n return timeInterval((date) => {\n if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);\n }, (date, step) => {\n if (date >= date) {\n if (step < 0) while (++step <= 0) {\n while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty\n } else while (--step >= 0) {\n while (offseti(date, +1), !test(date)) {} // eslint-disable-line no-empty\n }\n }\n });\n };\n\n if (count) {\n interval.count = (start, end) => {\n t0.setTime(+start), t1.setTime(+end);\n floori(t0), floori(t1);\n return Math.floor(count(t0, t1));\n };\n\n interval.every = (step) => {\n step = Math.floor(step);\n return !isFinite(step) || !(step > 0) ? null\n : !(step > 1) ? interval\n : interval.filter(field\n ? (d) => field(d) % step === 0\n : (d) => interval.count(0, d) % step === 0);\n };\n }\n\n return interval;\n}\n","import {timeInterval} from \"./interval.js\";\n\nexport const millisecond = timeInterval(() => {\n // noop\n}, (date, step) => {\n date.setTime(+date + step);\n}, (start, end) => {\n return end - start;\n});\n\n// An optimized implementation for this simple case.\nmillisecond.every = (k) => {\n k = Math.floor(k);\n if (!isFinite(k) || !(k > 0)) return null;\n if (!(k > 1)) return millisecond;\n return timeInterval((date) => {\n date.setTime(Math.floor(date / k) * k);\n }, (date, step) => {\n date.setTime(+date + step * k);\n }, (start, end) => {\n return (end - start) / k;\n });\n};\n\nexport const milliseconds = millisecond.range;\n","export const durationSecond = 1000;\nexport const durationMinute = durationSecond * 60;\nexport const durationHour = durationMinute * 60;\nexport const durationDay = durationHour * 24;\nexport const durationWeek = durationDay * 7;\nexport const durationMonth = durationDay * 30;\nexport const durationYear = durationDay * 365;\n","import {timeInterval} from \"./interval.js\";\nimport {durationSecond} from \"./duration.js\";\n\nexport const second = timeInterval((date) => {\n date.setTime(date - date.getMilliseconds());\n}, (date, step) => {\n date.setTime(+date + step * durationSecond);\n}, (start, end) => {\n return (end - start) / durationSecond;\n}, (date) => {\n return date.getUTCSeconds();\n});\n\nexport const seconds = second.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationMinute, durationSecond} from \"./duration.js\";\n\nexport const timeMinute = timeInterval((date) => {\n date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond);\n}, (date, step) => {\n date.setTime(+date + step * durationMinute);\n}, (start, end) => {\n return (end - start) / durationMinute;\n}, (date) => {\n return date.getMinutes();\n});\n\nexport const timeMinutes = timeMinute.range;\n\nexport const utcMinute = timeInterval((date) => {\n date.setUTCSeconds(0, 0);\n}, (date, step) => {\n date.setTime(+date + step * durationMinute);\n}, (start, end) => {\n return (end - start) / durationMinute;\n}, (date) => {\n return date.getUTCMinutes();\n});\n\nexport const utcMinutes = utcMinute.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationHour, durationMinute, durationSecond} from \"./duration.js\";\n\nexport const timeHour = timeInterval((date) => {\n date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute);\n}, (date, step) => {\n date.setTime(+date + step * durationHour);\n}, (start, end) => {\n return (end - start) / durationHour;\n}, (date) => {\n return date.getHours();\n});\n\nexport const timeHours = timeHour.range;\n\nexport const utcHour = timeInterval((date) => {\n date.setUTCMinutes(0, 0, 0);\n}, (date, step) => {\n date.setTime(+date + step * durationHour);\n}, (start, end) => {\n return (end - start) / durationHour;\n}, (date) => {\n return date.getUTCHours();\n});\n\nexport const utcHours = utcHour.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationDay, durationMinute} from \"./duration.js\";\n\nexport const timeDay = timeInterval(\n date => date.setHours(0, 0, 0, 0),\n (date, step) => date.setDate(date.getDate() + step),\n (start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay,\n date => date.getDate() - 1\n);\n\nexport const timeDays = timeDay.range;\n\nexport const utcDay = timeInterval((date) => {\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCDate(date.getUTCDate() + step);\n}, (start, end) => {\n return (end - start) / durationDay;\n}, (date) => {\n return date.getUTCDate() - 1;\n});\n\nexport const utcDays = utcDay.range;\n\nexport const unixDay = timeInterval((date) => {\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCDate(date.getUTCDate() + step);\n}, (start, end) => {\n return (end - start) / durationDay;\n}, (date) => {\n return Math.floor(date / durationDay);\n});\n\nexport const unixDays = unixDay.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationMinute, durationWeek} from \"./duration.js\";\n\nfunction timeWeekday(i) {\n return timeInterval((date) => {\n date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);\n date.setHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setDate(date.getDate() + step * 7);\n }, (start, end) => {\n return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;\n });\n}\n\nexport const timeSunday = timeWeekday(0);\nexport const timeMonday = timeWeekday(1);\nexport const timeTuesday = timeWeekday(2);\nexport const timeWednesday = timeWeekday(3);\nexport const timeThursday = timeWeekday(4);\nexport const timeFriday = timeWeekday(5);\nexport const timeSaturday = timeWeekday(6);\n\nexport const timeSundays = timeSunday.range;\nexport const timeMondays = timeMonday.range;\nexport const timeTuesdays = timeTuesday.range;\nexport const timeWednesdays = timeWednesday.range;\nexport const timeThursdays = timeThursday.range;\nexport const timeFridays = timeFriday.range;\nexport const timeSaturdays = timeSaturday.range;\n\nfunction utcWeekday(i) {\n return timeInterval((date) => {\n date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);\n date.setUTCHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setUTCDate(date.getUTCDate() + step * 7);\n }, (start, end) => {\n return (end - start) / durationWeek;\n });\n}\n\nexport const utcSunday = utcWeekday(0);\nexport const utcMonday = utcWeekday(1);\nexport const utcTuesday = utcWeekday(2);\nexport const utcWednesday = utcWeekday(3);\nexport const utcThursday = utcWeekday(4);\nexport const utcFriday = utcWeekday(5);\nexport const utcSaturday = utcWeekday(6);\n\nexport const utcSundays = utcSunday.range;\nexport const utcMondays = utcMonday.range;\nexport const utcTuesdays = utcTuesday.range;\nexport const utcWednesdays = utcWednesday.range;\nexport const utcThursdays = utcThursday.range;\nexport const utcFridays = utcFriday.range;\nexport const utcSaturdays = utcSaturday.range;\n","import {timeInterval} from \"./interval.js\";\n\nexport const timeMonth = timeInterval((date) => {\n date.setDate(1);\n date.setHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setMonth(date.getMonth() + step);\n}, (start, end) => {\n return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;\n}, (date) => {\n return date.getMonth();\n});\n\nexport const timeMonths = timeMonth.range;\n\nexport const utcMonth = timeInterval((date) => {\n date.setUTCDate(1);\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCMonth(date.getUTCMonth() + step);\n}, (start, end) => {\n return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;\n}, (date) => {\n return date.getUTCMonth();\n});\n\nexport const utcMonths = utcMonth.range;\n","import {timeInterval} from \"./interval.js\";\n\nexport const timeYear = timeInterval((date) => {\n date.setMonth(0, 1);\n date.setHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setFullYear(date.getFullYear() + step);\n}, (start, end) => {\n return end.getFullYear() - start.getFullYear();\n}, (date) => {\n return date.getFullYear();\n});\n\n// An optimized implementation for this simple case.\ntimeYear.every = (k) => {\n return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {\n date.setFullYear(Math.floor(date.getFullYear() / k) * k);\n date.setMonth(0, 1);\n date.setHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setFullYear(date.getFullYear() + step * k);\n });\n};\n\nexport const timeYears = timeYear.range;\n\nexport const utcYear = timeInterval((date) => {\n date.setUTCMonth(0, 1);\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCFullYear(date.getUTCFullYear() + step);\n}, (start, end) => {\n return end.getUTCFullYear() - start.getUTCFullYear();\n}, (date) => {\n return date.getUTCFullYear();\n});\n\n// An optimized implementation for this simple case.\nutcYear.every = (k) => {\n return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {\n date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);\n date.setUTCMonth(0, 1);\n date.setUTCHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setUTCFullYear(date.getUTCFullYear() + step * k);\n });\n};\n\nexport const utcYears = utcYear.range;\n","import {bisector, tickStep} from \"d3-array\";\nimport {durationDay, durationHour, durationMinute, durationMonth, durationSecond, durationWeek, durationYear} from \"./duration.js\";\nimport {millisecond} from \"./millisecond.js\";\nimport {second} from \"./second.js\";\nimport {timeMinute, utcMinute} from \"./minute.js\";\nimport {timeHour, utcHour} from \"./hour.js\";\nimport {timeDay, unixDay} from \"./day.js\";\nimport {timeSunday, utcSunday} from \"./week.js\";\nimport {timeMonth, utcMonth} from \"./month.js\";\nimport {timeYear, utcYear} from \"./year.js\";\n\nfunction ticker(year, month, week, day, hour, minute) {\n\n const tickIntervals = [\n [second, 1, durationSecond],\n [second, 5, 5 * durationSecond],\n [second, 15, 15 * durationSecond],\n [second, 30, 30 * durationSecond],\n [minute, 1, durationMinute],\n [minute, 5, 5 * durationMinute],\n [minute, 15, 15 * durationMinute],\n [minute, 30, 30 * durationMinute],\n [ hour, 1, durationHour ],\n [ hour, 3, 3 * durationHour ],\n [ hour, 6, 6 * durationHour ],\n [ hour, 12, 12 * durationHour ],\n [ day, 1, durationDay ],\n [ day, 2, 2 * durationDay ],\n [ week, 1, durationWeek ],\n [ month, 1, durationMonth ],\n [ month, 3, 3 * durationMonth ],\n [ year, 1, durationYear ]\n ];\n\n function ticks(start, stop, count) {\n const reverse = stop < start;\n if (reverse) [start, stop] = [stop, start];\n const interval = count && typeof count.range === \"function\" ? count : tickInterval(start, stop, count);\n const ticks = interval ? interval.range(start, +stop + 1) : []; // inclusive stop\n return reverse ? ticks.reverse() : ticks;\n }\n\n function tickInterval(start, stop, count) {\n const target = Math.abs(stop - start) / count;\n const i = bisector(([,, step]) => step).right(tickIntervals, target);\n if (i === tickIntervals.length) return year.every(tickStep(start / durationYear, stop / durationYear, count));\n if (i === 0) return millisecond.every(Math.max(tickStep(start, stop, count), 1));\n const [t, step] = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];\n return t.every(step);\n }\n\n return [ticks, tickInterval];\n}\n\nconst [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, unixDay, utcHour, utcMinute);\nconst [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute);\n\nexport {utcTicks, utcTickInterval, timeTicks, timeTickInterval};\n","import {\n timeDay,\n timeSunday,\n timeMonday,\n timeThursday,\n timeYear,\n utcDay,\n utcSunday,\n utcMonday,\n utcThursday,\n utcYear\n} from \"d3-time\";\n\nfunction localDate(d) {\n if (0 <= d.y && d.y < 100) {\n var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);\n date.setFullYear(d.y);\n return date;\n }\n return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);\n}\n\nfunction utcDate(d) {\n if (0 <= d.y && d.y < 100) {\n var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));\n date.setUTCFullYear(d.y);\n return date;\n }\n return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));\n}\n\nfunction newDate(y, m, d) {\n return {y: y, m: m, d: d, H: 0, M: 0, S: 0, L: 0};\n}\n\nexport default function formatLocale(locale) {\n var locale_dateTime = locale.dateTime,\n locale_date = locale.date,\n locale_time = locale.time,\n locale_periods = locale.periods,\n locale_weekdays = locale.days,\n locale_shortWeekdays = locale.shortDays,\n locale_months = locale.months,\n locale_shortMonths = locale.shortMonths;\n\n var periodRe = formatRe(locale_periods),\n periodLookup = formatLookup(locale_periods),\n weekdayRe = formatRe(locale_weekdays),\n weekdayLookup = formatLookup(locale_weekdays),\n shortWeekdayRe = formatRe(locale_shortWeekdays),\n shortWeekdayLookup = formatLookup(locale_shortWeekdays),\n monthRe = formatRe(locale_months),\n monthLookup = formatLookup(locale_months),\n shortMonthRe = formatRe(locale_shortMonths),\n shortMonthLookup = formatLookup(locale_shortMonths);\n\n var formats = {\n \"a\": formatShortWeekday,\n \"A\": formatWeekday,\n \"b\": formatShortMonth,\n \"B\": formatMonth,\n \"c\": null,\n \"d\": formatDayOfMonth,\n \"e\": formatDayOfMonth,\n \"f\": formatMicroseconds,\n \"g\": formatYearISO,\n \"G\": formatFullYearISO,\n \"H\": formatHour24,\n \"I\": formatHour12,\n \"j\": formatDayOfYear,\n \"L\": formatMilliseconds,\n \"m\": formatMonthNumber,\n \"M\": formatMinutes,\n \"p\": formatPeriod,\n \"q\": formatQuarter,\n \"Q\": formatUnixTimestamp,\n \"s\": formatUnixTimestampSeconds,\n \"S\": formatSeconds,\n \"u\": formatWeekdayNumberMonday,\n \"U\": formatWeekNumberSunday,\n \"V\": formatWeekNumberISO,\n \"w\": formatWeekdayNumberSunday,\n \"W\": formatWeekNumberMonday,\n \"x\": null,\n \"X\": null,\n \"y\": formatYear,\n \"Y\": formatFullYear,\n \"Z\": formatZone,\n \"%\": formatLiteralPercent\n };\n\n var utcFormats = {\n \"a\": formatUTCShortWeekday,\n \"A\": formatUTCWeekday,\n \"b\": formatUTCShortMonth,\n \"B\": formatUTCMonth,\n \"c\": null,\n \"d\": formatUTCDayOfMonth,\n \"e\": formatUTCDayOfMonth,\n \"f\": formatUTCMicroseconds,\n \"g\": formatUTCYearISO,\n \"G\": formatUTCFullYearISO,\n \"H\": formatUTCHour24,\n \"I\": formatUTCHour12,\n \"j\": formatUTCDayOfYear,\n \"L\": formatUTCMilliseconds,\n \"m\": formatUTCMonthNumber,\n \"M\": formatUTCMinutes,\n \"p\": formatUTCPeriod,\n \"q\": formatUTCQuarter,\n \"Q\": formatUnixTimestamp,\n \"s\": formatUnixTimestampSeconds,\n \"S\": formatUTCSeconds,\n \"u\": formatUTCWeekdayNumberMonday,\n \"U\": formatUTCWeekNumberSunday,\n \"V\": formatUTCWeekNumberISO,\n \"w\": formatUTCWeekdayNumberSunday,\n \"W\": formatUTCWeekNumberMonday,\n \"x\": null,\n \"X\": null,\n \"y\": formatUTCYear,\n \"Y\": formatUTCFullYear,\n \"Z\": formatUTCZone,\n \"%\": formatLiteralPercent\n };\n\n var parses = {\n \"a\": parseShortWeekday,\n \"A\": parseWeekday,\n \"b\": parseShortMonth,\n \"B\": parseMonth,\n \"c\": parseLocaleDateTime,\n \"d\": parseDayOfMonth,\n \"e\": parseDayOfMonth,\n \"f\": parseMicroseconds,\n \"g\": parseYear,\n \"G\": parseFullYear,\n \"H\": parseHour24,\n \"I\": parseHour24,\n \"j\": parseDayOfYear,\n \"L\": parseMilliseconds,\n \"m\": parseMonthNumber,\n \"M\": parseMinutes,\n \"p\": parsePeriod,\n \"q\": parseQuarter,\n \"Q\": parseUnixTimestamp,\n \"s\": parseUnixTimestampSeconds,\n \"S\": parseSeconds,\n \"u\": parseWeekdayNumberMonday,\n \"U\": parseWeekNumberSunday,\n \"V\": parseWeekNumberISO,\n \"w\": parseWeekdayNumberSunday,\n \"W\": parseWeekNumberMonday,\n \"x\": parseLocaleDate,\n \"X\": parseLocaleTime,\n \"y\": parseYear,\n \"Y\": parseFullYear,\n \"Z\": parseZone,\n \"%\": parseLiteralPercent\n };\n\n // These recursive directive definitions must be deferred.\n formats.x = newFormat(locale_date, formats);\n formats.X = newFormat(locale_time, formats);\n formats.c = newFormat(locale_dateTime, formats);\n utcFormats.x = newFormat(locale_date, utcFormats);\n utcFormats.X = newFormat(locale_time, utcFormats);\n utcFormats.c = newFormat(locale_dateTime, utcFormats);\n\n function newFormat(specifier, formats) {\n return function(date) {\n var string = [],\n i = -1,\n j = 0,\n n = specifier.length,\n c,\n pad,\n format;\n\n if (!(date instanceof Date)) date = new Date(+date);\n\n while (++i < n) {\n if (specifier.charCodeAt(i) === 37) {\n string.push(specifier.slice(j, i));\n if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);\n else pad = c === \"e\" ? \" \" : \"0\";\n if (format = formats[c]) c = format(date, pad);\n string.push(c);\n j = i + 1;\n }\n }\n\n string.push(specifier.slice(j, i));\n return string.join(\"\");\n };\n }\n\n function newParse(specifier, Z) {\n return function(string) {\n var d = newDate(1900, undefined, 1),\n i = parseSpecifier(d, specifier, string += \"\", 0),\n week, day;\n if (i != string.length) return null;\n\n // If a UNIX timestamp is specified, return it.\n if (\"Q\" in d) return new Date(d.Q);\n if (\"s\" in d) return new Date(d.s * 1000 + (\"L\" in d ? d.L : 0));\n\n // If this is utcParse, never use the local timezone.\n if (Z && !(\"Z\" in d)) d.Z = 0;\n\n // The am-pm flag is 0 for AM, and 1 for PM.\n if (\"p\" in d) d.H = d.H % 12 + d.p * 12;\n\n // If the month was not specified, inherit from the quarter.\n if (d.m === undefined) d.m = \"q\" in d ? d.q : 0;\n\n // Convert day-of-week and week-of-year to day-of-year.\n if (\"V\" in d) {\n if (d.V < 1 || d.V > 53) return null;\n if (!(\"w\" in d)) d.w = 1;\n if (\"Z\" in d) {\n week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay();\n week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week);\n week = utcDay.offset(week, (d.V - 1) * 7);\n d.y = week.getUTCFullYear();\n d.m = week.getUTCMonth();\n d.d = week.getUTCDate() + (d.w + 6) % 7;\n } else {\n week = localDate(newDate(d.y, 0, 1)), day = week.getDay();\n week = day > 4 || day === 0 ? timeMonday.ceil(week) : timeMonday(week);\n week = timeDay.offset(week, (d.V - 1) * 7);\n d.y = week.getFullYear();\n d.m = week.getMonth();\n d.d = week.getDate() + (d.w + 6) % 7;\n }\n } else if (\"W\" in d || \"U\" in d) {\n if (!(\"w\" in d)) d.w = \"u\" in d ? d.u % 7 : \"W\" in d ? 1 : 0;\n day = \"Z\" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay();\n d.m = 0;\n d.d = \"W\" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;\n }\n\n // If a time zone is specified, all fields are interpreted as UTC and then\n // offset according to the specified time zone.\n if (\"Z\" in d) {\n d.H += d.Z / 100 | 0;\n d.M += d.Z % 100;\n return utcDate(d);\n }\n\n // Otherwise, all fields are in local time.\n return localDate(d);\n };\n }\n\n function parseSpecifier(d, specifier, string, j) {\n var i = 0,\n n = specifier.length,\n m = string.length,\n c,\n parse;\n\n while (i < n) {\n if (j >= m) return -1;\n c = specifier.charCodeAt(i++);\n if (c === 37) {\n c = specifier.charAt(i++);\n parse = parses[c in pads ? specifier.charAt(i++) : c];\n if (!parse || ((j = parse(d, string, j)) < 0)) return -1;\n } else if (c != string.charCodeAt(j++)) {\n return -1;\n }\n }\n\n return j;\n }\n\n function parsePeriod(d, string, i) {\n var n = periodRe.exec(string.slice(i));\n return n ? (d.p = periodLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseShortWeekday(d, string, i) {\n var n = shortWeekdayRe.exec(string.slice(i));\n return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseWeekday(d, string, i) {\n var n = weekdayRe.exec(string.slice(i));\n return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseShortMonth(d, string, i) {\n var n = shortMonthRe.exec(string.slice(i));\n return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseMonth(d, string, i) {\n var n = monthRe.exec(string.slice(i));\n return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseLocaleDateTime(d, string, i) {\n return parseSpecifier(d, locale_dateTime, string, i);\n }\n\n function parseLocaleDate(d, string, i) {\n return parseSpecifier(d, locale_date, string, i);\n }\n\n function parseLocaleTime(d, string, i) {\n return parseSpecifier(d, locale_time, string, i);\n }\n\n function formatShortWeekday(d) {\n return locale_shortWeekdays[d.getDay()];\n }\n\n function formatWeekday(d) {\n return locale_weekdays[d.getDay()];\n }\n\n function formatShortMonth(d) {\n return locale_shortMonths[d.getMonth()];\n }\n\n function formatMonth(d) {\n return locale_months[d.getMonth()];\n }\n\n function formatPeriod(d) {\n return locale_periods[+(d.getHours() >= 12)];\n }\n\n function formatQuarter(d) {\n return 1 + ~~(d.getMonth() / 3);\n }\n\n function formatUTCShortWeekday(d) {\n return locale_shortWeekdays[d.getUTCDay()];\n }\n\n function formatUTCWeekday(d) {\n return locale_weekdays[d.getUTCDay()];\n }\n\n function formatUTCShortMonth(d) {\n return locale_shortMonths[d.getUTCMonth()];\n }\n\n function formatUTCMonth(d) {\n return locale_months[d.getUTCMonth()];\n }\n\n function formatUTCPeriod(d) {\n return locale_periods[+(d.getUTCHours() >= 12)];\n }\n\n function formatUTCQuarter(d) {\n return 1 + ~~(d.getUTCMonth() / 3);\n }\n\n return {\n format: function(specifier) {\n var f = newFormat(specifier += \"\", formats);\n f.toString = function() { return specifier; };\n return f;\n },\n parse: function(specifier) {\n var p = newParse(specifier += \"\", false);\n p.toString = function() { return specifier; };\n return p;\n },\n utcFormat: function(specifier) {\n var f = newFormat(specifier += \"\", utcFormats);\n f.toString = function() { return specifier; };\n return f;\n },\n utcParse: function(specifier) {\n var p = newParse(specifier += \"\", true);\n p.toString = function() { return specifier; };\n return p;\n }\n };\n}\n\nvar pads = {\"-\": \"\", \"_\": \" \", \"0\": \"0\"},\n numberRe = /^\\s*\\d+/, // note: ignores next directive\n percentRe = /^%/,\n requoteRe = /[\\\\^$*+?|[\\]().{}]/g;\n\nfunction pad(value, fill, width) {\n var sign = value < 0 ? \"-\" : \"\",\n string = (sign ? -value : value) + \"\",\n length = string.length;\n return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);\n}\n\nfunction requote(s) {\n return s.replace(requoteRe, \"\\\\$&\");\n}\n\nfunction formatRe(names) {\n return new RegExp(\"^(?:\" + names.map(requote).join(\"|\") + \")\", \"i\");\n}\n\nfunction formatLookup(names) {\n return new Map(names.map((name, i) => [name.toLowerCase(), i]));\n}\n\nfunction parseWeekdayNumberSunday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.w = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekdayNumberMonday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.u = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberSunday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.U = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberISO(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.V = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberMonday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.W = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseFullYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 4));\n return n ? (d.y = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;\n}\n\nfunction parseZone(d, string, i) {\n var n = /^(Z)|([+-]\\d\\d)(?::?(\\d\\d))?/.exec(string.slice(i, i + 6));\n return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || \"00\")), i + n[0].length) : -1;\n}\n\nfunction parseQuarter(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.q = n[0] * 3 - 3, i + n[0].length) : -1;\n}\n\nfunction parseMonthNumber(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.m = n[0] - 1, i + n[0].length) : -1;\n}\n\nfunction parseDayOfMonth(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.d = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseDayOfYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 3));\n return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseHour24(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.H = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMinutes(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.M = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseSeconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.S = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMilliseconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 3));\n return n ? (d.L = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMicroseconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 6));\n return n ? (d.L = Math.floor(n[0] / 1000), i + n[0].length) : -1;\n}\n\nfunction parseLiteralPercent(d, string, i) {\n var n = percentRe.exec(string.slice(i, i + 1));\n return n ? i + n[0].length : -1;\n}\n\nfunction parseUnixTimestamp(d, string, i) {\n var n = numberRe.exec(string.slice(i));\n return n ? (d.Q = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseUnixTimestampSeconds(d, string, i) {\n var n = numberRe.exec(string.slice(i));\n return n ? (d.s = +n[0], i + n[0].length) : -1;\n}\n\nfunction formatDayOfMonth(d, p) {\n return pad(d.getDate(), p, 2);\n}\n\nfunction formatHour24(d, p) {\n return pad(d.getHours(), p, 2);\n}\n\nfunction formatHour12(d, p) {\n return pad(d.getHours() % 12 || 12, p, 2);\n}\n\nfunction formatDayOfYear(d, p) {\n return pad(1 + timeDay.count(timeYear(d), d), p, 3);\n}\n\nfunction formatMilliseconds(d, p) {\n return pad(d.getMilliseconds(), p, 3);\n}\n\nfunction formatMicroseconds(d, p) {\n return formatMilliseconds(d, p) + \"000\";\n}\n\nfunction formatMonthNumber(d, p) {\n return pad(d.getMonth() + 1, p, 2);\n}\n\nfunction formatMinutes(d, p) {\n return pad(d.getMinutes(), p, 2);\n}\n\nfunction formatSeconds(d, p) {\n return pad(d.getSeconds(), p, 2);\n}\n\nfunction formatWeekdayNumberMonday(d) {\n var day = d.getDay();\n return day === 0 ? 7 : day;\n}\n\nfunction formatWeekNumberSunday(d, p) {\n return pad(timeSunday.count(timeYear(d) - 1, d), p, 2);\n}\n\nfunction dISO(d) {\n var day = d.getDay();\n return (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);\n}\n\nfunction formatWeekNumberISO(d, p) {\n d = dISO(d);\n return pad(timeThursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2);\n}\n\nfunction formatWeekdayNumberSunday(d) {\n return d.getDay();\n}\n\nfunction formatWeekNumberMonday(d, p) {\n return pad(timeMonday.count(timeYear(d) - 1, d), p, 2);\n}\n\nfunction formatYear(d, p) {\n return pad(d.getFullYear() % 100, p, 2);\n}\n\nfunction formatYearISO(d, p) {\n d = dISO(d);\n return pad(d.getFullYear() % 100, p, 2);\n}\n\nfunction formatFullYear(d, p) {\n return pad(d.getFullYear() % 10000, p, 4);\n}\n\nfunction formatFullYearISO(d, p) {\n var day = d.getDay();\n d = (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);\n return pad(d.getFullYear() % 10000, p, 4);\n}\n\nfunction formatZone(d) {\n var z = d.getTimezoneOffset();\n return (z > 0 ? \"-\" : (z *= -1, \"+\"))\n + pad(z / 60 | 0, \"0\", 2)\n + pad(z % 60, \"0\", 2);\n}\n\nfunction formatUTCDayOfMonth(d, p) {\n return pad(d.getUTCDate(), p, 2);\n}\n\nfunction formatUTCHour24(d, p) {\n return pad(d.getUTCHours(), p, 2);\n}\n\nfunction formatUTCHour12(d, p) {\n return pad(d.getUTCHours() % 12 || 12, p, 2);\n}\n\nfunction formatUTCDayOfYear(d, p) {\n return pad(1 + utcDay.count(utcYear(d), d), p, 3);\n}\n\nfunction formatUTCMilliseconds(d, p) {\n return pad(d.getUTCMilliseconds(), p, 3);\n}\n\nfunction formatUTCMicroseconds(d, p) {\n return formatUTCMilliseconds(d, p) + \"000\";\n}\n\nfunction formatUTCMonthNumber(d, p) {\n return pad(d.getUTCMonth() + 1, p, 2);\n}\n\nfunction formatUTCMinutes(d, p) {\n return pad(d.getUTCMinutes(), p, 2);\n}\n\nfunction formatUTCSeconds(d, p) {\n return pad(d.getUTCSeconds(), p, 2);\n}\n\nfunction formatUTCWeekdayNumberMonday(d) {\n var dow = d.getUTCDay();\n return dow === 0 ? 7 : dow;\n}\n\nfunction formatUTCWeekNumberSunday(d, p) {\n return pad(utcSunday.count(utcYear(d) - 1, d), p, 2);\n}\n\nfunction UTCdISO(d) {\n var day = d.getUTCDay();\n return (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);\n}\n\nfunction formatUTCWeekNumberISO(d, p) {\n d = UTCdISO(d);\n return pad(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2);\n}\n\nfunction formatUTCWeekdayNumberSunday(d) {\n return d.getUTCDay();\n}\n\nfunction formatUTCWeekNumberMonday(d, p) {\n return pad(utcMonday.count(utcYear(d) - 1, d), p, 2);\n}\n\nfunction formatUTCYear(d, p) {\n return pad(d.getUTCFullYear() % 100, p, 2);\n}\n\nfunction formatUTCYearISO(d, p) {\n d = UTCdISO(d);\n return pad(d.getUTCFullYear() % 100, p, 2);\n}\n\nfunction formatUTCFullYear(d, p) {\n return pad(d.getUTCFullYear() % 10000, p, 4);\n}\n\nfunction formatUTCFullYearISO(d, p) {\n var day = d.getUTCDay();\n d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);\n return pad(d.getUTCFullYear() % 10000, p, 4);\n}\n\nfunction formatUTCZone() {\n return \"+0000\";\n}\n\nfunction formatLiteralPercent() {\n return \"%\";\n}\n\nfunction formatUnixTimestamp(d) {\n return +d;\n}\n\nfunction formatUnixTimestampSeconds(d) {\n return Math.floor(+d / 1000);\n}\n","import formatLocale from \"./locale.js\";\n\nvar locale;\nexport var timeFormat;\nexport var timeParse;\nexport var utcFormat;\nexport var utcParse;\n\ndefaultLocale({\n dateTime: \"%x, %X\",\n date: \"%-m/%-d/%Y\",\n time: \"%-I:%M:%S %p\",\n periods: [\"AM\", \"PM\"],\n days: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"],\n shortDays: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n months: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"],\n shortMonths: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n});\n\nexport default function defaultLocale(definition) {\n locale = formatLocale(definition);\n timeFormat = locale.format;\n timeParse = locale.parse;\n utcFormat = locale.utcFormat;\n utcParse = locale.utcParse;\n return locale;\n}\n","import {timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeTicks, timeTickInterval} from \"d3-time\";\nimport {timeFormat} from \"d3-time-format\";\nimport continuous, {copy} from \"./continuous.js\";\nimport {initRange} from \"./init.js\";\nimport nice from \"./nice.js\";\n\nfunction date(t) {\n return new Date(t);\n}\n\nfunction number(t) {\n return t instanceof Date ? +t : +new Date(+t);\n}\n\nexport function calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format) {\n var scale = continuous(),\n invert = scale.invert,\n domain = scale.domain;\n\n var formatMillisecond = format(\".%L\"),\n formatSecond = format(\":%S\"),\n formatMinute = format(\"%I:%M\"),\n formatHour = format(\"%I %p\"),\n formatDay = format(\"%a %d\"),\n formatWeek = format(\"%b %d\"),\n formatMonth = format(\"%B\"),\n formatYear = format(\"%Y\");\n\n function tickFormat(date) {\n return (second(date) < date ? formatMillisecond\n : minute(date) < date ? formatSecond\n : hour(date) < date ? formatMinute\n : day(date) < date ? formatHour\n : month(date) < date ? (week(date) < date ? formatDay : formatWeek)\n : year(date) < date ? formatMonth\n : formatYear)(date);\n }\n\n scale.invert = function(y) {\n return new Date(invert(y));\n };\n\n scale.domain = function(_) {\n return arguments.length ? domain(Array.from(_, number)) : domain().map(date);\n };\n\n scale.ticks = function(interval) {\n var d = domain();\n return ticks(d[0], d[d.length - 1], interval == null ? 10 : interval);\n };\n\n scale.tickFormat = function(count, specifier) {\n return specifier == null ? tickFormat : format(specifier);\n };\n\n scale.nice = function(interval) {\n var d = domain();\n if (!interval || typeof interval.range !== \"function\") interval = tickInterval(d[0], d[d.length - 1], interval == null ? 10 : interval);\n return interval ? domain(nice(d, interval)) : scale;\n };\n\n scale.copy = function() {\n return copy(scale, calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format));\n };\n\n return scale;\n}\n\nexport default function time() {\n return initRange.apply(calendar(timeTicks, timeTickInterval, timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments);\n}\n","export default function nice(domain, interval) {\n domain = domain.slice();\n\n var i0 = 0,\n i1 = domain.length - 1,\n x0 = domain[i0],\n x1 = domain[i1],\n t;\n\n if (x1 < x0) {\n t = i0, i0 = i1, i1 = t;\n t = x0, x0 = x1, x1 = t;\n }\n\n domain[i0] = interval.floor(x0);\n domain[i1] = interval.ceil(x1);\n return domain;\n}\n","export default function(x) {\n return function constant() {\n return x;\n };\n}\n","export const abs = Math.abs;\nexport const atan2 = Math.atan2;\nexport const cos = Math.cos;\nexport const max = Math.max;\nexport const min = Math.min;\nexport const sin = Math.sin;\nexport const sqrt = Math.sqrt;\n\nexport const epsilon = 1e-12;\nexport const pi = Math.PI;\nexport const halfPi = pi / 2;\nexport const tau = 2 * pi;\n\nexport function acos(x) {\n return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);\n}\n\nexport function asin(x) {\n return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);\n}\n","import {Path} from \"d3-path\";\n\nexport function withPath(shape) {\n let digits = 3;\n\n shape.digits = function(_) {\n if (!arguments.length) return digits;\n if (_ == null) {\n digits = null;\n } else {\n const d = Math.floor(_);\n if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);\n digits = d;\n }\n return shape;\n };\n\n return () => new Path(digits);\n}\n","import constant from \"./constant.js\";\nimport {abs, acos, asin, atan2, cos, epsilon, halfPi, max, min, pi, sin, sqrt, tau} from \"./math.js\";\nimport {withPath} from \"./path.js\";\n\nfunction arcInnerRadius(d) {\n return d.innerRadius;\n}\n\nfunction arcOuterRadius(d) {\n return d.outerRadius;\n}\n\nfunction arcStartAngle(d) {\n return d.startAngle;\n}\n\nfunction arcEndAngle(d) {\n return d.endAngle;\n}\n\nfunction arcPadAngle(d) {\n return d && d.padAngle; // Note: optional!\n}\n\nfunction intersect(x0, y0, x1, y1, x2, y2, x3, y3) {\n var x10 = x1 - x0, y10 = y1 - y0,\n x32 = x3 - x2, y32 = y3 - y2,\n t = y32 * x10 - x32 * y10;\n if (t * t < epsilon) return;\n t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;\n return [x0 + t * x10, y0 + t * y10];\n}\n\n// Compute perpendicular offset line of length rc.\n// http://mathworld.wolfram.com/Circle-LineIntersection.html\nfunction cornerTangents(x0, y0, x1, y1, r1, rc, cw) {\n var x01 = x0 - x1,\n y01 = y0 - y1,\n lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),\n ox = lo * y01,\n oy = -lo * x01,\n x11 = x0 + ox,\n y11 = y0 + oy,\n x10 = x1 + ox,\n y10 = y1 + oy,\n x00 = (x11 + x10) / 2,\n y00 = (y11 + y10) / 2,\n dx = x10 - x11,\n dy = y10 - y11,\n d2 = dx * dx + dy * dy,\n r = r1 - rc,\n D = x11 * y10 - x10 * y11,\n d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),\n cx0 = (D * dy - dx * d) / d2,\n cy0 = (-D * dx - dy * d) / d2,\n cx1 = (D * dy + dx * d) / d2,\n cy1 = (-D * dx + dy * d) / d2,\n dx0 = cx0 - x00,\n dy0 = cy0 - y00,\n dx1 = cx1 - x00,\n dy1 = cy1 - y00;\n\n // Pick the closer of the two intersection points.\n // TODO Is there a faster way to determine which intersection to use?\n if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;\n\n return {\n cx: cx0,\n cy: cy0,\n x01: -ox,\n y01: -oy,\n x11: cx0 * (r1 / r - 1),\n y11: cy0 * (r1 / r - 1)\n };\n}\n\nexport default function() {\n var innerRadius = arcInnerRadius,\n outerRadius = arcOuterRadius,\n cornerRadius = constant(0),\n padRadius = null,\n startAngle = arcStartAngle,\n endAngle = arcEndAngle,\n padAngle = arcPadAngle,\n context = null,\n path = withPath(arc);\n\n function arc() {\n var buffer,\n r,\n r0 = +innerRadius.apply(this, arguments),\n r1 = +outerRadius.apply(this, arguments),\n a0 = startAngle.apply(this, arguments) - halfPi,\n a1 = endAngle.apply(this, arguments) - halfPi,\n da = abs(a1 - a0),\n cw = a1 > a0;\n\n if (!context) context = buffer = path();\n\n // Ensure that the outer radius is always larger than the inner radius.\n if (r1 < r0) r = r1, r1 = r0, r0 = r;\n\n // Is it a point?\n if (!(r1 > epsilon)) context.moveTo(0, 0);\n\n // Or is it a circle or annulus?\n else if (da > tau - epsilon) {\n context.moveTo(r1 * cos(a0), r1 * sin(a0));\n context.arc(0, 0, r1, a0, a1, !cw);\n if (r0 > epsilon) {\n context.moveTo(r0 * cos(a1), r0 * sin(a1));\n context.arc(0, 0, r0, a1, a0, cw);\n }\n }\n\n // Or is it a circular or annular sector?\n else {\n var a01 = a0,\n a11 = a1,\n a00 = a0,\n a10 = a1,\n da0 = da,\n da1 = da,\n ap = padAngle.apply(this, arguments) / 2,\n rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),\n rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),\n rc0 = rc,\n rc1 = rc,\n t0,\n t1;\n\n // Apply padding? Note that since r1 β‰₯ r0, da1 β‰₯ da0.\n if (rp > epsilon) {\n var p0 = asin(rp / r0 * sin(ap)),\n p1 = asin(rp / r1 * sin(ap));\n if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;\n else da0 = 0, a00 = a10 = (a0 + a1) / 2;\n if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;\n else da1 = 0, a01 = a11 = (a0 + a1) / 2;\n }\n\n var x01 = r1 * cos(a01),\n y01 = r1 * sin(a01),\n x10 = r0 * cos(a10),\n y10 = r0 * sin(a10);\n\n // Apply rounded corners?\n if (rc > epsilon) {\n var x11 = r1 * cos(a11),\n y11 = r1 * sin(a11),\n x00 = r0 * cos(a00),\n y00 = r0 * sin(a00),\n oc;\n\n // Restrict the corner radius according to the sector angle. If this\n // intersection fails, it’s probably because the arc is too small, so\n // disable the corner radius entirely.\n if (da < pi) {\n if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {\n var ax = x01 - oc[0],\n ay = y01 - oc[1],\n bx = x11 - oc[0],\n by = y11 - oc[1],\n kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),\n lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);\n rc0 = min(rc, (r0 - lc) / (kc - 1));\n rc1 = min(rc, (r1 - lc) / (kc + 1));\n } else {\n rc0 = rc1 = 0;\n }\n }\n }\n\n // Is the sector collapsed to a line?\n if (!(da1 > epsilon)) context.moveTo(x01, y01);\n\n // Does the sector’s outer ring have rounded corners?\n else if (rc1 > epsilon) {\n t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);\n t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);\n\n context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);\n context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the outer ring just a circular arc?\n else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);\n\n // Is there no inner ring, and it’s a circular sector?\n // Or perhaps it’s an annular sector collapsed due to padding?\n if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);\n\n // Does the sector’s inner ring (or point) have rounded corners?\n else if (rc0 > epsilon) {\n t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);\n t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);\n\n context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);\n context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the inner ring just a circular arc?\n else context.arc(0, 0, r0, a10, a00, cw);\n }\n\n context.closePath();\n\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n arc.centroid = function() {\n var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,\n a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;\n return [cos(a) * r, sin(a) * r];\n };\n\n arc.innerRadius = function(_) {\n return arguments.length ? (innerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : innerRadius;\n };\n\n arc.outerRadius = function(_) {\n return arguments.length ? (outerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : outerRadius;\n };\n\n arc.cornerRadius = function(_) {\n return arguments.length ? (cornerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : cornerRadius;\n };\n\n arc.padRadius = function(_) {\n return arguments.length ? (padRadius = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), arc) : padRadius;\n };\n\n arc.startAngle = function(_) {\n return arguments.length ? (startAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : startAngle;\n };\n\n arc.endAngle = function(_) {\n return arguments.length ? (endAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : endAngle;\n };\n\n arc.padAngle = function(_) {\n return arguments.length ? (padAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : padAngle;\n };\n\n arc.context = function(_) {\n return arguments.length ? ((context = _ == null ? null : _), arc) : context;\n };\n\n return arc;\n}\n","export var slice = Array.prototype.slice;\n\nexport default function(x) {\n return typeof x === \"object\" && \"length\" in x\n ? x // Array, TypedArray, NodeList, array-like\n : Array.from(x); // Map, Set, iterable, string, or anything else\n}\n","function Linear(context) {\n this._context = context;\n}\n\nLinear.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // falls through\n default: this._context.lineTo(x, y); break;\n }\n }\n};\n\nexport default function(context) {\n return new Linear(context);\n}\n","export function x(p) {\n return p[0];\n}\n\nexport function y(p) {\n return p[1];\n}\n","import array from \"./array.js\";\nimport constant from \"./constant.js\";\nimport curveLinear from \"./curve/linear.js\";\nimport {withPath} from \"./path.js\";\nimport {x as pointX, y as pointY} from \"./point.js\";\n\nexport default function(x, y) {\n var defined = constant(true),\n context = null,\n curve = curveLinear,\n output = null,\n path = withPath(line);\n\n x = typeof x === \"function\" ? x : (x === undefined) ? pointX : constant(x);\n y = typeof y === \"function\" ? y : (y === undefined) ? pointY : constant(y);\n\n function line(data) {\n var i,\n n = (data = array(data)).length,\n d,\n defined0 = false,\n buffer;\n\n if (context == null) output = curve(buffer = path());\n\n for (i = 0; i <= n; ++i) {\n if (!(i < n && defined(d = data[i], i, data)) === defined0) {\n if (defined0 = !defined0) output.lineStart();\n else output.lineEnd();\n }\n if (defined0) output.point(+x(d, i, data), +y(d, i, data));\n }\n\n if (buffer) return output = null, buffer + \"\" || null;\n }\n\n line.x = function(_) {\n return arguments.length ? (x = typeof _ === \"function\" ? _ : constant(+_), line) : x;\n };\n\n line.y = function(_) {\n return arguments.length ? (y = typeof _ === \"function\" ? _ : constant(+_), line) : y;\n };\n\n line.defined = function(_) {\n return arguments.length ? (defined = typeof _ === \"function\" ? _ : constant(!!_), line) : defined;\n };\n\n line.curve = function(_) {\n return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;\n };\n\n line.context = function(_) {\n return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;\n };\n\n return line;\n}\n","import array from \"./array.js\";\nimport constant from \"./constant.js\";\nimport curveLinear from \"./curve/linear.js\";\nimport line from \"./line.js\";\nimport {withPath} from \"./path.js\";\nimport {x as pointX, y as pointY} from \"./point.js\";\n\nexport default function(x0, y0, y1) {\n var x1 = null,\n defined = constant(true),\n context = null,\n curve = curveLinear,\n output = null,\n path = withPath(area);\n\n x0 = typeof x0 === \"function\" ? x0 : (x0 === undefined) ? pointX : constant(+x0);\n y0 = typeof y0 === \"function\" ? y0 : (y0 === undefined) ? constant(0) : constant(+y0);\n y1 = typeof y1 === \"function\" ? y1 : (y1 === undefined) ? pointY : constant(+y1);\n\n function area(data) {\n var i,\n j,\n k,\n n = (data = array(data)).length,\n d,\n defined0 = false,\n buffer,\n x0z = new Array(n),\n y0z = new Array(n);\n\n if (context == null) output = curve(buffer = path());\n\n for (i = 0; i <= n; ++i) {\n if (!(i < n && defined(d = data[i], i, data)) === defined0) {\n if (defined0 = !defined0) {\n j = i;\n output.areaStart();\n output.lineStart();\n } else {\n output.lineEnd();\n output.lineStart();\n for (k = i - 1; k >= j; --k) {\n output.point(x0z[k], y0z[k]);\n }\n output.lineEnd();\n output.areaEnd();\n }\n }\n if (defined0) {\n x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);\n output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);\n }\n }\n\n if (buffer) return output = null, buffer + \"\" || null;\n }\n\n function arealine() {\n return line().defined(defined).curve(curve).context(context);\n }\n\n area.x = function(_) {\n return arguments.length ? (x0 = typeof _ === \"function\" ? _ : constant(+_), x1 = null, area) : x0;\n };\n\n area.x0 = function(_) {\n return arguments.length ? (x0 = typeof _ === \"function\" ? _ : constant(+_), area) : x0;\n };\n\n area.x1 = function(_) {\n return arguments.length ? (x1 = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), area) : x1;\n };\n\n area.y = function(_) {\n return arguments.length ? (y0 = typeof _ === \"function\" ? _ : constant(+_), y1 = null, area) : y0;\n };\n\n area.y0 = function(_) {\n return arguments.length ? (y0 = typeof _ === \"function\" ? _ : constant(+_), area) : y0;\n };\n\n area.y1 = function(_) {\n return arguments.length ? (y1 = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), area) : y1;\n };\n\n area.lineX0 =\n area.lineY0 = function() {\n return arealine().x(x0).y(y0);\n };\n\n area.lineY1 = function() {\n return arealine().x(x0).y(y1);\n };\n\n area.lineX1 = function() {\n return arealine().x(x1).y(y0);\n };\n\n area.defined = function(_) {\n return arguments.length ? (defined = typeof _ === \"function\" ? _ : constant(!!_), area) : defined;\n };\n\n area.curve = function(_) {\n return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;\n };\n\n area.context = function(_) {\n return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;\n };\n\n return area;\n}\n","import curveLinear from \"./linear.js\";\n\nexport var curveRadialLinear = curveRadial(curveLinear);\n\nfunction Radial(curve) {\n this._curve = curve;\n}\n\nRadial.prototype = {\n areaStart: function() {\n this._curve.areaStart();\n },\n areaEnd: function() {\n this._curve.areaEnd();\n },\n lineStart: function() {\n this._curve.lineStart();\n },\n lineEnd: function() {\n this._curve.lineEnd();\n },\n point: function(a, r) {\n this._curve.point(r * Math.sin(a), r * -Math.cos(a));\n }\n};\n\nexport default function curveRadial(curve) {\n\n function radial(context) {\n return new Radial(curve(context));\n }\n\n radial._curve = curve;\n\n return radial;\n}\n","import curveRadial, {curveRadialLinear} from \"./curve/radial.js\";\nimport line from \"./line.js\";\n\nexport function lineRadial(l) {\n var c = l.curve;\n\n l.angle = l.x, delete l.x;\n l.radius = l.y, delete l.y;\n\n l.curve = function(_) {\n return arguments.length ? c(curveRadial(_)) : c()._curve;\n };\n\n return l;\n}\n\nexport default function() {\n return lineRadial(line().curve(curveRadialLinear));\n}\n","import {pi, sqrt, tau} from \"../math.js\";\n\nexport default {\n draw(context, size) {\n const r = sqrt(size / pi);\n context.moveTo(r, 0);\n context.arc(0, 0, r, 0, tau);\n }\n};\n","import {sqrt} from \"../math.js\";\n\nconst sqrt3 = sqrt(3);\n\nexport default {\n draw(context, size) {\n const y = -sqrt(size / (sqrt3 * 3));\n context.moveTo(0, y * 2);\n context.lineTo(-sqrt3 * y, -y);\n context.lineTo(sqrt3 * y, -y);\n context.closePath();\n }\n};\n","import constant from \"./constant.js\";\nimport {withPath} from \"./path.js\";\nimport asterisk from \"./symbol/asterisk.js\";\nimport circle from \"./symbol/circle.js\";\nimport cross from \"./symbol/cross.js\";\nimport diamond from \"./symbol/diamond.js\";\nimport diamond2 from \"./symbol/diamond2.js\";\nimport plus from \"./symbol/plus.js\";\nimport square from \"./symbol/square.js\";\nimport square2 from \"./symbol/square2.js\";\nimport star from \"./symbol/star.js\";\nimport triangle from \"./symbol/triangle.js\";\nimport triangle2 from \"./symbol/triangle2.js\";\nimport wye from \"./symbol/wye.js\";\nimport times from \"./symbol/times.js\";\n\n// These symbols are designed to be filled.\nexport const symbolsFill = [\n circle,\n cross,\n diamond,\n square,\n star,\n triangle,\n wye\n];\n\n// These symbols are designed to be stroked (with a width of 1.5px and round caps).\nexport const symbolsStroke = [\n circle,\n plus,\n times,\n triangle2,\n asterisk,\n square2,\n diamond2\n];\n\nexport default function Symbol(type, size) {\n let context = null,\n path = withPath(symbol);\n\n type = typeof type === \"function\" ? type : constant(type || circle);\n size = typeof size === \"function\" ? size : constant(size === undefined ? 64 : +size);\n\n function symbol() {\n let buffer;\n if (!context) context = buffer = path();\n type.apply(this, arguments).draw(context, +size.apply(this, arguments));\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n symbol.type = function(_) {\n return arguments.length ? (type = typeof _ === \"function\" ? _ : constant(_), symbol) : type;\n };\n\n symbol.size = function(_) {\n return arguments.length ? (size = typeof _ === \"function\" ? _ : constant(+_), symbol) : size;\n };\n\n symbol.context = function(_) {\n return arguments.length ? (context = _ == null ? null : _, symbol) : context;\n };\n\n return symbol;\n}\n","function sign(x) {\n return x < 0 ? -1 : 1;\n}\n\n// Calculate the slopes of the tangents (Hermite-type interpolation) based on\n// the following paper: Steffen, M. 1990. A Simple Method for Monotonic\n// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.\n// NOV(II), P. 443, 1990.\nfunction slope3(that, x2, y2) {\n var h0 = that._x1 - that._x0,\n h1 = x2 - that._x1,\n s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),\n s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),\n p = (s0 * h1 + s1 * h0) / (h0 + h1);\n return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;\n}\n\n// Calculate a one-sided slope.\nfunction slope2(that, t) {\n var h = that._x1 - that._x0;\n return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;\n}\n\n// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations\n// \"you can express cubic Hermite interpolation in terms of cubic BΓ©zier curves\n// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1\".\nfunction point(that, t0, t1) {\n var x0 = that._x0,\n y0 = that._y0,\n x1 = that._x1,\n y1 = that._y1,\n dx = (x1 - x0) / 3;\n that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);\n}\n\nfunction MonotoneX(context) {\n this._context = context;\n}\n\nMonotoneX.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 =\n this._t0 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x1, this._y1); break;\n case 3: point(this, this._t0, slope2(this, this._t0)); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n var t1 = NaN;\n\n x = +x, y = +y;\n if (x === this._x1 && y === this._y1) return; // Ignore coincident points.\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;\n default: point(this, this._t0, t1 = slope3(this, x, y)); break;\n }\n\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n this._t0 = t1;\n }\n}\n\nfunction MonotoneY(context) {\n this._context = new ReflectContext(context);\n}\n\n(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {\n MonotoneX.prototype.point.call(this, y, x);\n};\n\nfunction ReflectContext(context) {\n this._context = context;\n}\n\nReflectContext.prototype = {\n moveTo: function(x, y) { this._context.moveTo(y, x); },\n closePath: function() { this._context.closePath(); },\n lineTo: function(x, y) { this._context.lineTo(y, x); },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }\n};\n\nexport function monotoneX(context) {\n return new MonotoneX(context);\n}\n\nexport function monotoneY(context) {\n return new MonotoneY(context);\n}\n","export function Transform(k, x, y) {\n this.k = k;\n this.x = x;\n this.y = y;\n}\n\nTransform.prototype = {\n constructor: Transform,\n scale: function(k) {\n return k === 1 ? this : new Transform(this.k * k, this.x, this.y);\n },\n translate: function(x, y) {\n return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);\n },\n apply: function(point) {\n return [point[0] * this.k + this.x, point[1] * this.k + this.y];\n },\n applyX: function(x) {\n return x * this.k + this.x;\n },\n applyY: function(y) {\n return y * this.k + this.y;\n },\n invert: function(location) {\n return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];\n },\n invertX: function(x) {\n return (x - this.x) / this.k;\n },\n invertY: function(y) {\n return (y - this.y) / this.k;\n },\n rescaleX: function(x) {\n return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));\n },\n rescaleY: function(y) {\n return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));\n },\n toString: function() {\n return \"translate(\" + this.x + \",\" + this.y + \") scale(\" + this.k + \")\";\n }\n};\n\nexport var identity = new Transform(1, 0, 0);\n\ntransform.prototype = Transform.prototype;\n\nexport default function transform(node) {\n while (!node.__zoom) if (!(node = node.parentNode)) return identity;\n return node.__zoom;\n}\n","export function formatDate(date: Date, format: string): string {\n return format\n .replace(\"YYYY\", String(date.getFullYear()))\n .replace(\"MM\", String(date.getMonth() + 1).padStart(2, \"0\"))\n .replace(\"DD\", String(date.getDate()).padStart(2, \"0\"))\n .replace(\"HH\", String(date.getHours()).padStart(2, \"0\"))\n .replace(\"hh\", String((date.getHours() % 12) || 12).padStart(2, \"0\"))\n .replace(\"mm\", String(date.getMinutes()).padStart(2, \"0\"))\n .replace(\"ss\", String(date.getSeconds()).padStart(2, \"0\"));\n}\n\nexport function formatNumber(value: number, format: string): string {\n // Examples:\n // \"0.00\" = 2 decimals\n if (/0\\.0+/.test(format)) {\n const decimals = format.split(\".\")[1].length;\n return value.toFixed(decimals);\n }\n\n // \"value unit\"\n if (format.includes(\"value\") && format.includes(\"unit\")) {\n return format\n .replace(\"value\", String(value))\n .replace(\"unit\", \"\");\n }\n\n return String(value); // fallback\n}\n\n\nexport function defaultDateFormatter(d: Date): string {\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: true,\n }).format(d);\n}\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","import React, { useEffect, useRef, useState } from \"react\";\nimport * as d3 from \"d3\";\n\n\nimport { CSSProperties } from \"react\";\nimport \"../../src/index.css\"\nimport { validateRequiredProps } from \"../helpers/validate\";\nimport { defaultDateFormatter, formatDate, formatNumber } from \"../helpers/formatDate\";\n\nfunction computeBottomMargin(ticks: string[]) {\n if (!ticks.length) return 40;\n\n // estimate width of text based on average character width\n const longest = ticks.reduce((a, b) => (a.length > b.length ? a : b), \"\");\n const approxCharWidth = 7; // px\n const approximateTextWidth = longest.length * approxCharWidth;\n\n // because labels rotate -30deg, height β‰ˆ width * sin(30Β°)\n const estimatedHeight = approximateTextWidth * 0.5;\n\n return Math.max(40, estimatedHeight + 20); // + extra padding\n}\n\n/* ------------------------ Types ------------------------ */\nexport interface ChartDataPoint {\n timestamp: number;\n value: number;\n}\ntype WidgetState = {\n value?: any;\n loading?: boolean;\n error?: string | null; // βœ… matches your React state\n};\n\n\ninterface ChartStyleSet {\n container?: CSSProperties;\n title?: CSSProperties;\n tooltip?: CSSProperties;\n axis?: CSSProperties;\n chart?: {\n strokeColor?: string;\n strokeWidth?: number;\n gradientColors?: [string, string];\n dotRadius?: number;\n };\n fontFamily:string\n}\ntype StylesInput =\n | ChartStyleSet\n | ((state: WidgetState) => ChartStyleSet);\n\nexport interface ChartWidgetProps {\n client: any;\n nodeId: string;\n variable: string;\n from:number,\n to:number,\n limit?:number,\n title?: string;\n styles?: StylesInput;\n tooltipFormatter?: (d: ChartDataPoint) => string;\n tickCount?: number; // number of ticks on x axis (default: 4)\n tickFormatter?: (d: Date) => string; // optional custom formatter\n xTickFormat?: string | ((d: Date) => string); // date formatting\n yTickFormat?: string | ((v: number) => string); // numeric formatting\n tooltipFormat?: string | ((d: ChartDataPoint) => string);\n onStyleChange?:(data:ChartDataPoint[]) =>{}\n}\n\n/* ------------------------ Helpers ------------------------ */\nconst normalizeSx = (sx: Record | undefined): Record => {\n if (!sx) return {};\n if (Array.isArray(sx)) return Object.assign({}, ...sx);\n if (typeof sx === \"function\") return sx({}) as Record;\n return sx as Record;\n};\n\nconst toDateSafe = (ts: number): Date => {\n // If ts < 1e12, treat as seconds -> convert to ms\n if (ts < 1e12) return new Date(ts * 1000);\n\n return new Date(ts);\n};\n\n/* ------------------------ Defaults ------------------------ */\nconst defaultFontFamily = \"Roboto, sans-serif\";\n\nconst defaultStyles: Required = {\n container: {\n width: 400,\n height: 250,\n padding: 2,\n margin: 0,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",\n borderRadius: 10,\n boxSizing: \"border-box\",\ngap:0,\n background: \"rgb(248, 249, 250)\",\n border: \"1px solid rgba(211, 216, 220, 1)\",\n \n\n textAlign: \"center\",\n fontFamily: defaultFontFamily,\n },\n title: {\n \n fontWeight: 600,\n color: \"rgba(0,0,0,0.75)\",\n // marginBottom: 1,\n fontFamily: defaultFontFamily,\n },\n tooltip: {\n background: \"rgba(0,0,0,0.75)\",\n\n color: \"#ffffff\",\n\n borderRadius: \"6px\",\n padding: \"6px 10px\",\n fontSize: \"12px\",\n fontFamily: defaultFontFamily,\n },\n axis: {\n color: \"#666\",\n fontSize: \"11px\",\n fontFamily:defaultFontFamily,\n\n },\n chart: {\n strokeColor: \"#1e88e5\",\n strokeWidth: 2,\n gradientColors: [\"#1e88e5\", \"#90caf9\"],\n dotRadius: 4,\n\n },\n fontFamily:defaultFontFamily\n\n \n};\n\n\n// ---- ChartWidget ----\nexport const ChartWidget: React.FC = ({\n client,\n nodeId,\n variable,\n from,\n to,\n limit=20,\n title = \"Latest Data\",\n styles = {},\n tooltipFormatter = (d) =>\n `${new Date(\n new Date(d.timestamp < 1e12 ? d.timestamp * 1000 : d.timestamp)\n ).toLocaleString(undefined, {\n month: \"short\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: true,\n })}: ${d.value}`,\n tickCount = 4,\n tickFormatter,\n xTickFormat,\n yTickFormat,\n tooltipFormat,\n onStyleChange\n}) => {\n\n validateRequiredProps(\n \"Chart Widget\",\n { client, nodeId, variable,from,to },\n [\"client\", \"nodeId\", \"variable\",\"from time\",\"to time\"]\n );\n\n const resolvedXFormatter =\n typeof xTickFormat === \"string\"\n ? (d: Date) => formatDate(d, xTickFormat)\n : xTickFormat;\n\nconst resolvedYFormatter =\n typeof yTickFormat === \"string\"\n ? (v: number) => formatNumber(v, yTickFormat)\n : yTickFormat;\n\nconst resolvedTooltipFormatter =\n typeof tooltipFormat === \"string\"\n ? (d: ChartDataPoint) =>\n `${formatDate(toDateSafe(d.timestamp), tooltipFormat)}: ${d.value}`\n : tooltipFormat;\n\n\n // Refs + state\n const svgRef = useRef(null);\n const tooltipNodeRef = useRef(null);\n const [data, setData] = useState([\n // { timestamp: Date.now() - 60000, value: 33 },\n // { timestamp: Date.now() - 30000, value: 44 },\n // { timestamp: Date.now(), value: 38 },\n ]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(null);\n const [node, setNode] = useState(null);\n\n\n const state = { data, loading, error }; // <-- your widget’s internal state\n\n// Resolve function or static style object\nconst [dynamicStyles, setDynamicStyles] = useState>({});\n\nconst baseResolvedStyles =\n typeof styles === \"function\" ? styles(state) : styles || {};\n\nconst resolvedStyles = {\n container: { ...baseResolvedStyles.container, ...dynamicStyles?.container },\n title: { ...baseResolvedStyles.title, ...dynamicStyles?.title },\n tooltip: { ...baseResolvedStyles.tooltip, ...dynamicStyles?.tooltip },\n chart: { ...baseResolvedStyles.chart, ...dynamicStyles?.chart },\n axis: { ...baseResolvedStyles.axis, ...dynamicStyles?.axis },\n fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily,\n};\n const mountedRef = useRef(false);\n const failureCountRef = useRef(0);\n const isFetchingRef = useRef(false);\n const MAX_FAILURES = 3;\n\n // ---- Normalize Styles ----\n const containerSx = normalizeSx(resolvedStyles?.container);\n const titleSx = normalizeSx(resolvedStyles?.title);\n const tooltipSx = normalizeSx(resolvedStyles?.tooltip);\n const chartSx = resolvedStyles.chart ?? {};\n const axisSx = normalizeSx(resolvedStyles?.axis);\n\n // --- Container dimensions with TypeScript-safe default ---\n const containerDefaults: any = defaultStyles.container!;\n const width = containerSx.width ?? containerDefaults.width;\n const height = containerSx.height ?? containerDefaults.height;\n\n\n // --- Font family handling ---\n const globalFontFamily = resolvedStyles?.fontFamily ?? \"Roboto\";\n const labelFontFamily = titleSx.fontFamily ?? globalFontFamily;\n\n\n \n\n\n\n\n // --- Scaled font sizes ---\n const baseFont = Math.min(Number(width), Number(height)) * 0.15;\n\n // --- Compute font sizes dynamically if not provided by user ---\n const labelFont = (resolvedStyles?.title as any)?.fontSize ?? baseFont * 0.6;\n\n \n const strokeColor = chartSx.strokeColor ?? defaultStyles.chart.strokeColor;\n const strokeWidth = chartSx.strokeWidth ?? defaultStyles.chart.strokeWidth;\n const gradientColors =\n chartSx.gradientColors ?? defaultStyles.chart.gradientColors;\nconst dotRadius = chartSx.dotRadius ?? defaultStyles.chart.dotRadius;\n // ---- Fetch Node ----\n useEffect(() => {\n if (!client || !nodeId) return;\n const anedya = (client as any)._anedya;\n const createdNode = anedya?.NewNode?.(client, nodeId);\n setNode(createdNode);\n }, [client, nodeId]);\n\n // ---- Fetch Data ----\n useEffect(() => {\n mountedRef.current = true;\n if (\n !node\n // || data.length>0\n )\n return;\n\n const fetchData = async () => {\n if (isFetchingRef.current || failureCountRef.current >= MAX_FAILURES)\n return;\n isFetchingRef.current = true;\n\n try {\n setLoading(true);\n setError(null);\n // const currentTime = Date.now();\n // const twentyFourHoursAgo = currentTime - 86400 * 1000;\n//1732420983000\n//1763956983000\n const req = {\n variable,\n from: from,\n to: to,\n limit: limit,\n order: \"asc\",\n };\n const res = await node.getData(req);\n\n if (!mountedRef.current) return;\n\n if (res.isSuccess && res.isDataAvailable) {\n setData(res.data);\n setError(\"\");\n\n } else {\n console.error(\"error fetching data:\", res.error);\n setError(res.error.errorMessage);\n }\n failureCountRef.current = 0;\n } catch (err: any) {\n console.error(\"Error fetching chart data:\", err);\n setData([]);\n setError(err?.message ?? \"Failed to fetch data\");\n failureCountRef.current += 1;\n } finally {\n setLoading(false);\n if (mountedRef.current) isFetchingRef.current = false;\n }\n };\n\n fetchData();\n return () => {\n mountedRef.current = false;\n };\n }, [node, variable]);\n\n /* ------------------------ D3 render (dots + line + area + tooltip + axes) ------------------------ */\n useEffect(() => {\n if (!svgRef.current) return;\n const svgEl = svgRef.current;\n const svg = d3.select(svgEl);\n svg.selectAll(\"*\").remove();\n\n // If no data, nothing to draw\n if (!data || data.length === 0) {\n return;\n }\n\n\n\n // // --- COMPUTE SCALES --- //\n // const tempDates = data.map((d) => toDateSafe(d.timestamp));\n // const tempX = d3.scaleTime().domain(d3.extent(tempDates) as [Date, Date]).range([0, 1]); // temp range\n // const provisionalTicks = tempX.ticks(tickCount);\n\n // const tickLabels = provisionalTicks.map((d) =>\n // resolvedXFormatter ? resolvedXFormatter(d) : defaultDateFormatter(d)\n // );\n\n // const dynamicBottom = computeBottomMargin(tickLabels);\n\n // // --- NOW REAL MARGINS --- //\n // const margin = { top: 20, right: 20, bottom: dynamicBottom, left: 50 };\n\n // // recompute chart area\n // const chartW = Math.max(10, width - margin.left - margin.right);\n // const chartH = Math.max(10, height - margin.top - margin.bottom);\n\n // // recompute x with real width\n // tempX.range([0, chartW]);\n\n //.attr(\"transform\", \"rotate(-30)\")\n//margins (leave extra bottom space for rotated ticks)\n const margin = { top: 20, right: 20, bottom: 130, left: 50 };\n const chartW = Math.max(10, width - margin.left - margin.right);\n const chartH = Math.max(10, height - margin.top - margin.bottom);\n\n // group\n const g = svg.append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n // parse / convert timestamps to Date safely\n const dates = data.map((d) => toDateSafe(d.timestamp));\n const x = d3.scaleTime().domain(d3.extent(dates) as [Date, Date]).range([0, chartW]);\n const maxY = Math.max(10, d3.max(data, (d) => Number(d.value)) ?? 10);\n const y = d3.scaleLinear().domain([0, maxY]).nice().range([chartH, 0]);\n\n // gradient\n const safeGradient = gradientColors ?? [\"#1e88e5\", \"#90caf9\"];\n const safeStroke = strokeColor ?? \"#1e88e5\";\n const safeWidth = strokeWidth ?? 2;\n const safeDotRadius = dotRadius ?? 4\n const defs = svg.append(\"defs\");\n\n const gradient = defs\n .append(\"linearGradient\")\n .attr(\"id\", \"chartGradient\")\n .attr(\"x1\", \"0%\")\n .attr(\"y1\", \"0%\")\n .attr(\"x2\", \"0%\")\n .attr(\"y2\", \"100%\");\n gradient\n .append(\"stop\")\n .attr(\"offset\", \"0%\")\n .attr(\"stop-color\", safeGradient[0])\n .attr(\"stop-opacity\", 0.5);\n gradient\n .append(\"stop\")\n .attr(\"offset\", \"100%\")\n .attr(\"stop-color\", safeGradient[1])\n .attr(\"stop-opacity\", 0);\n\n // area\n const area = d3\n .area()\n .x((d) => x(toDateSafe(d.timestamp)))\n .y0(chartH)\n .y1((d) => y(d.value))\n .curve(d3.curveMonotoneX);\n\n g.append(\"path\").datum(data).attr(\"fill\", \"url(#chartGradient)\").attr(\"d\", area);\n\n // line\n const line = d3\n .line()\n .x((d) => x(toDateSafe(d.timestamp)))\n .y((d) => y(d.value))\n .curve(d3.curveMonotoneX);\n\n g.append(\"path\")\n .datum(data)\n .attr(\"fill\", \"none\")\n .attr(\"stroke\", safeStroke)\n .attr(\"stroke-width\", safeWidth)\n .attr(\"d\", line);\n\n // dots\n const dotR = computeDotRadius(chartW, chartH, safeDotRadius);\n const dots = g\n .selectAll(\".dot\")\n .data(data)\n .enter()\n .append(\"circle\")\n .attr(\"class\", \"dot\")\n .attr(\"cx\", (d) => x(toDateSafe(d.timestamp)))\n .attr(\"cy\", (d) => y(d.value))\n .attr(\"r\", dotR)\n .attr(\"fill\", safeStroke)\n .style(\"cursor\", \"default\");\n\n // Tooltip (create single DOM node appended to body)\n // Reuse tooltip div if present\n let tooltipDiv = tooltipNodeRef.current;\n if (!tooltipDiv) {\n tooltipDiv = document.createElement(\"div\");\n tooltipNodeRef.current = tooltipDiv;\n document.body.appendChild(tooltipDiv);\n }\n // apply tooltip styles (inline)\n const tooltipDefaults: any = defaultStyles.tooltip;\n tooltipDiv.style.position = \"absolute\";\n tooltipDiv.style.pointerEvents = \"none\";\n tooltipDiv.style.opacity = \"0\";\n tooltipDiv.style.background = (tooltipSx.backgroundColor ?? tooltipDefaults.background) as string;\n tooltipDiv.style.color = (tooltipSx.color ?? tooltipDefaults.color) as string;\n tooltipDiv.style.borderRadius = (tooltipSx.borderRadius ?? tooltipDefaults.borderRadius) as string;\n tooltipDiv.style.padding = (tooltipSx.padding ?? tooltipDefaults.padding) as string;\n tooltipDiv.style.fontSize = (tooltipSx.fontSize ?? tooltipDefaults.fontSize) as string;\n tooltipDiv.style.transition = \"opacity 120ms\";\n\n // interactions\n dots\n .on(\"mouseover\", function (event, d: ChartDataPoint) {\n tooltipDiv!.style.opacity = \"1\";\n tooltipDiv!.innerHTML = resolvedTooltipFormatter\n ? resolvedTooltipFormatter(d)\n : tooltipFormatter(d);\n })\n .on(\"mousemove\", function (event) {\n // place tooltip near pointer but keep inside window\n const pad = 8;\n const left = Math.min(window.innerWidth - 200, event.pageX + pad);\n const top = Math.max(8, event.pageY - 36);\n tooltipDiv!.style.left = `${left}px`;\n tooltipDiv!.style.top = `${top}px`;\n })\n .on(\"mouseout\", function () {\n tooltipDiv!.style.opacity = \"0\";\n });\n\n // axes - bottom x with custom tick formatting and rotated labels\n const xAxis = d3\n .axisBottom(x)\n .ticks(tickCount)\n .tickFormat((d) => {\n if (resolvedXFormatter) return resolvedXFormatter(d as Date);\n return defaultDateFormatter(d as Date);\n });\n\n\n const axisDefaults : any = defaultStyles.axis\n g.append(\"g\")\n .attr(\"transform\", `translate(0,${chartH})`)\n .call(xAxis)\n .selectAll(\"text\")\n .attr(\"transform\", \"rotate(-30)\")\n .style(\"text-anchor\", \"end\")\n .style(\"font-size\", (axisSx.fontSize ?? axisDefaults.fontSize) as string)\n .style(\"fill\", (axisSx.color ?? axisDefaults.color) as string)\n .style(\"font-family\", (axisSx.fontFamily ?? axisDefaults.fontFamily) as string);\n\n g.append(\"g\")\n .call(d3.axisLeft(y).ticks(5).tickFormat((v) => {\n if (resolvedYFormatter) return resolvedYFormatter(v as number);\n return String(v);\n }))\n .selectAll(\"text\")\n .style(\"font-size\", (axisSx.fontSize ?? axisDefaults.fontSize) as string)\n .style(\"fill\", (axisSx.color ?? axisDefaults.color) as string)\n .style(\"font-family\", (axisSx.fontFamily ?? axisDefaults.fontFamily) as string);\n\n // keep axes inside container by clipping overflow\n // Add clipPath so elements don't overflow container boundaries visually\n const clipId = `clip-${Math.random().toString(36).slice(2, 9)}`;\n svg\n .append(\"defs\")\n .append(\"clipPath\")\n .attr(\"id\", clipId)\n .append(\"rect\")\n .attr(\"width\", width)\n .attr(\"height\", height);\n svg.attr(\"clip-path\", `url(#${clipId})`);\n\n // cleanup on effect re-run\n return () => {\n // remove tooltip div if created by this component\n if (tooltipNodeRef.current) {\n try {\n tooltipNodeRef.current.remove();\n } catch {}\n tooltipNodeRef.current = null;\n }\n svg.selectAll(\"*\").remove();\n };\n }, [\n data,\n width,\n height,\n strokeColor,\n strokeWidth,\n gradientColors,\n dotRadius,\n tickCount,\n tickFormatter,\n tooltipFormatter,\n axisSx,\n tooltipSx,\n ]);\n\n\n\n // Whenever value changes, allow user to modify styles dynamically\n useEffect(() => {\n if (typeof onStyleChange === \"function\") {\n const updated = onStyleChange(data);\n if (updated && typeof updated === \"object\") {\n setDynamicStyles(updated);\n }\n }\n }, [data]);\n \n /* ------------------------ Helpers ------------------------ */\n function computeDotRadius(chartW: number, chartH: number, requested: number) {\n // scale dot radius a bit relative to min dimension but honor requested if provided\n const base = Math.max(2, Math.min(chartW, chartH) * 0.012);\n return requested ?? Math.round(base);\n }\n // --- Merge styles safely ---\n const mergedContainerSx: CSSProperties = {\n ...defaultStyles.container,\n ...containerSx,\n \n };\n const mergedLabelSx: CSSProperties = {\n ...defaultStyles.title,\n fontSize: labelFont,\n ...titleSx,\n fontFamily: labelFontFamily,\n };\n\n\n return (\n
\n {title && (\n \n {title}\n \n )}\n {loading ? (\n \n
\n \n ) : error ? (\n
\n \n{error}\n
\n\n \n ) : data?.length === 0?\n
\n \n{ \"No data available\"}\n
\n\n :\n (\n \n )}\n \n );\n};\n\n//add customizable toolips, stroke width and color, and title obvs , timestamps for get data request\n//match customization and failsafes to latest data\n//documentation\n//modify anedya client as well\n//adjust rateLimitMs\n//how do i also ensure that the y axis labels dont crpss the container card border , all labels are contained within th container card\n\n//ftick format functions\n//responsiveness\n//frequesncy of ticks\n//show all widgets\n//documentation\n//consistent widget default styling , default color palette and theme\n//beta launch\n//how to add docs in npm --- add them in read me\n","import React, { PureComponent, SVGProps } from \"react\";\n\nclass SVGBase extends PureComponent> {\n render() {\n const { children, ...props } = this.props;\n return {children};\n }\n}\n\nexport default SVGBase;\n","import React, { PureComponent } from \"react\";\nimport { line, scaleLinear } from \"d3\";\n\n\n\nclass Pointer extends PureComponent {\n render() {\n const {\n width = 12.5,\n head = (0.8 * 250) / 2 - 5,\n tail = 5,\n value = -5,\n tooltip = \"\",\n center = { x: 125, y: 135 },\n minAngle,\n maxAngle,\n disabled\n } :any= this.props;\n\n const pointerLine = line()([\n [width / 2, 0],\n [0, -head],\n [-(width / 2), 0],\n [0, tail],\n [width / 2, 0]\n ]);\n const valueScale = scaleLinear()\n .domain([0, 1])\n .range([minAngle, maxAngle]);\n const pointerValue = valueScale(value);\n\n const showTooltip = (e: React.MouseEvent, text: string) => {\n const tooltip = document.getElementById(\"gauge-tooltip\");\n if (!tooltip || !text) return;\n\n tooltip.textContent = text;\n tooltip.style.opacity = \"1\";\n tooltip.style.transform = \"translateY(0px)\";\n moveTooltip(e);\n};\n\nconst moveTooltip = (e: React.MouseEvent) => {\n const tooltip = document.getElementById(\"gauge-tooltip\");\n if (!tooltip) return;\n\n tooltip.style.left = e.clientX + 10 + \"px\";\n tooltip.style.top = e.clientY - 20 + \"px\";\n};\n\nconst hideTooltip = () => {\n const tooltip = document.getElementById(\"gauge-tooltip\");\n if (!tooltip) return;\n\n tooltip.style.opacity = \"0\";\n tooltip.style.transform = \"translateY(-5px)\";\n};\n\n return (\n // \n \n showTooltip(e, tooltip)}\n onMouseMove={(e) => moveTooltip(e)}\n onMouseLeave={hideTooltip}\n >\n {tooltip && {tooltip}}\n \n \n // \n );\n }\n}\n\nexport default Pointer;\n","import React, { PureComponent } from \"react\";\nimport { symbol, symbolTriangle } from \"d3\";\n\nclass InvertedTriangle extends PureComponent {\n render() {\n const { center, disabled }:any = this.props;\n return (\n \n );\n }\n}\n\nexport default InvertedTriangle;\n","import React, { PureComponent } from \"react\";\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\n\n const renderUnitText = (text: string, style: UnitStyle) => {\n switch (style) {\n case \"superscript\":\n return {text};\n case \"subscript\":\n return {text};\n default:\n return {text};\n }\n};\n\nclass UnitOfMeasurement extends PureComponent {\n render() {\n const { value, disabled, center, offsetText,uom ,mergedValueSx,mergedUnitSx ,formatted,...rest}:any = this.props;\n\n return (\n // \n // {value+\" \"+uom}\n // \n\n \n \n {/* UNIT LEFT */}\n {formatted.unitText && formatted.position === \"left\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n\n {/* VALUE */}\n
{formatted.text}
\n\n {/* UNIT RIGHT */}\n {formatted.unitText && formatted.position === \"right\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n\n {/* UNIT TOP */}\n {formatted.unitText && formatted.position === \"top\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n\n {/* UNIT BOTTOM */}\n {formatted.unitText && formatted.position === \"bottom\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n \n \n );\n }\n}\n\nexport default UnitOfMeasurement;\n","import React, { PureComponent } from \"react\";\nimport { scaleLinear, lineRadial } from \"d3\";\n\n/** Ratio of arc to size of container. */\nconst baseRatio = 0.8;\n\n/** Resolution of arc. */\nconst length = 40;\n\nclass GaugeArc extends PureComponent {\n render() {\n const {\n inset = 0,\n min = 0,\n max = 1,\n maxAngle,\n minAngle,\n center = { x: 125, y: 135 },\n ...props\n }:any = this.props;\n\n /** Calculate max angle of arc from degrees to radians */\n const maxRatio = maxAngle / 180;\n const arcMax = Math.PI * maxRatio;\n\n /** Calculate min angle of arc from degrees to radians */\n const minRatio = minAngle / 180;\n const arcMin = Math.PI * minRatio;\n\n /** Linear map from [0,1] to [-135,135] degrees in radians */\n const refToRads = scaleLinear()\n .domain([0, 1])\n .range([arcMin, arcMax]);\n\n /** Render scale to map [0,length - 1] to [minAndle, maxAngle] for rendering */\n const arcScale = scaleLinear()\n .domain([0, length - 1])\n .range([refToRads(min), refToRads(max)]);\n\n /** Actual path function to generate path. */\n const arc:any = lineRadial()\n .angle((d, i) => arcScale(i))\n .radius((250 * baseRatio) / 2 - inset);\n\n const arcPath = arc({ length });\n\n return (\n \n );\n }\n}\n\nexport default GaugeArc;\n","import React, { PureComponent } from \"react\";\nimport { scaleLinear, line } from \"d3\";\n\nconst getTickRef = (tickCount:any, minVal:any, maxVal:any, minAngle:any, maxAngle:any) => {\n if (tickCount % 2 === 0)\n console.warn(\n \"Ticks should be odd numbered to ensure a tick in in the middle of the gauge.\"\n );\n\n const idxToRef = scaleLinear()\n .domain([0, tickCount - 1])\n .range([0, 1]);\n\n const idxToVal = scaleLinear()\n .domain([0, tickCount - 1])\n .range([minVal, maxVal]);\n\n const refToDeg = scaleLinear()\n .domain([0, 1])\n .range([minAngle, maxAngle]);\n\n return [...Array(tickCount)].map((v, i) => ({\n index: i,\n val: idxToVal(i),\n deg: refToDeg(idxToRef(i))\n }));\n};\n\nconst tickLineLong = line()\n .x(0)\n .y((d, i) => i)(Array.from({ length: 35 }));\n\nconst tickLineShort = line()\n .x(0)\n .y((d, i) => i)(Array.from({ length: 12 }));\n\nclass Label extends PureComponent {\n render() {\n const {\n disabled,\n center,\n tickCount,\n min,\n max,\n maxAngle,\n minAngle,\n offsetText,\n length = 300 / 2 - 30\n }:any = this.props;\n\n const ticks = getTickRef(tickCount, min, max, minAngle, maxAngle);\n\n return ticks.map(({ val, deg, index }) => {\n return (\n \n \n \n {Number(val)}\n \n \n );\n });\n }\n}\n\nexport default Label;\n","import React, { PureComponent } from \"react\";\n\nclass Gradient extends PureComponent {\n render() {\n const { start, end, id, disabled }:any = this.props;\n return (\n \n \n \n \n \n \n );\n }\n}\n\nexport default Gradient;\n","import React, { useCallback, useMemo } from \"react\";\nimport { scaleLinear } from \"d3\";\n\nimport {\n SVGBase,\n Pointer,\n InvertedTriangle,\n UnitOfMeasurement,\n GaugeArc,\n Label\n} from \"./components\";\n\nimport \"../../index.css\"\nconst defaultSize = 250;\n\nconst Gauge = ({\n height=400,\n width=400,\n disabled=false,\n value = -1,\n min = 0,\n max = 100,\n maxAngle = 135,\n minAngle = -135,\n tickCount = 5,\n arcSegments = [{ min: 0, max: 1, color: \"skyblue\" }],\n labelProps = {\n offsetText: -7.5\n },\n uom = \"\",\n uomProps = {\n offsetText: -10,\n //-7.5\n },\n pointerLabel = \"\",\n mergedUnitSx={},\n mergedValueSx={},\n formatted,\n ...props\n}:any) => {\n const gaugeOrigin = {\n x: 140,\n y: 140\n };\n\n const valueScale = useCallback(\n scaleLinear()\n .domain([min, max])\n .range([0, 1]),\n [min, max]\n );\n\n /** Value scaled to [0,1] */\n const valueRef = useMemo(() => valueScale(value), [value, valueScale]);\n\n return (\n <>\n \n \n \n {arcSegments.map(({ min, max, color}:any, idx:any) => (\n \n {/* {typeof node === \"function\" ? node(disabled) : node} */}\n \n \n ))}\n \n \n \n \n \n );\n};\n\nexport default Gauge;\n","\n// GaugeWidget.tsx\nimport React, { useEffect, useRef, useMemo, useState } from \"react\";\nimport * as d3 from \"d3\";\n\nimport ReactDOM from \"react-dom\";\n\nimport Gauge from \"../components/Gauge/Gauge\";\nimport useGradient from \"../components/Gauge/hooks/useGradient\";\nimport { CSSProperties } from \"react\";\nimport { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\nimport { validateRequiredProps } from \"../helpers/validate\";\n\n/**\n * Helper: Normalize SxProps to plain object (like in your other widgets)\n */\nconst normalizeSx = (\n sx: Record | undefined\n): Record => {\n if (!sx) return {};\n if (Array.isArray(sx)) return Object.assign({}, ...sx);\n if (typeof sx === \"function\") return sx({}) as Record;\n return sx as Record;\n};\nconst defaultFontFamily = \"Roboto, sans-serif\";\n\ninterface GaugeArcStyle {\n trackColor?: string;\n progressColor?: string;\n progressStroke?: string;\n fontSize?: string | number;\n fontFamily?: string;\n}\n\nconst defaultArcSx: GaugeArcStyle = {\n trackColor: \"#e6e6e6\", // light background arc\n progressColor: \"#4caf50\", // the β€œfilled” arc part\n progressStroke: \"none\",\n fontSize: \"20px\",\n fontFamily: defaultFontFamily,\n};\nconst defaultSubtitleSx: CSSProperties = {\n fontSize: \"12px\",\n color: \"#666\",\n fontFamily: defaultFontFamily,\n};\n\n\n/* ---------------------- Types ---------------------- */\n\nexport interface Zone {\n from: number; // inclusive\n to: number; // exclusive\n color: string;\n}\ntype WidgetState = {\n value?: any;\n loading?: boolean;\n error?: string | null; // βœ… matches your React state\n};\n\nexport interface GaugeStyleSet {\n container?: CSSProperties;\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\nsubtitle?: CSSProperties;\n arc?: GaugeArcStyle; \n fontFamily?: string; // optional global font family for all 3\n}\n\n\ntype StylesInput =\n | GaugeStyleSet\n | ((state: WidgetState) => GaugeStyleSet);\n\n\n\nexport interface GaugeMetrics {\n maxRadius: number;\n valueAngleDeg: number;\n valueAngleRad: number;\n startAngleDeg: number;\n endAngleDeg: number;\n innerRadius: number;\n outerRadius: number;\n cx: number;\n cy: number;\n}\n\nexport interface GaugeWidgetProps {\n client: any;\n nodeId: string;\n variable: string;\n min?: number; // default 0\n max?: number; // default 100\n startAngleDeg?: number; // degrees, default -90 (left) for semi-circle\n endAngleDeg?: number; // degrees, default 90 (right) for semi-circle\n thickness?: number; // thickness of the arc (absolute px) β€” default: 0.2 * radius\n zones?: Zone[]; // colored zones, optional (defaults provided)\n showNeedle?: boolean; // draw a needle for the value\n needleColor?: string;\n needleWidth?: number;\n title?: string;\n subtitle?: string;\nstyles?: StylesInput;\n disabled?: boolean; //for pointer label\n tickCount?: number;\n unit?: string;\n uomOffset?: number;\n labelOffset?: number;\n // callback to receive computed values (optional)\n onMetrics?: (metrics: GaugeMetrics) => void;\n // function that returns the inner text (defaults to \"value / max\")\n valueText?: (opts: {\n value?: number;\n valueMin: number;\n valueMax: number;\n }) => string;\n onStyleChange?:(value:number) =>{};\n displayText?: DisplayTextFormatter;\n}\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\n\ninterface DisplayTextResult {\n text: string;\n unitText?: string;\n position?: UnitPosition;\n unitStyle?: UnitStyle;\n}\n\ntype DisplayTextFormatter = (\n value: number,\n unit?: string\n) => DisplayTextResult;\n\n\n/* ---------------------- Defaults ---------------------- */\n\nconst defaultZones: Zone[] = [\n { from: 0, to: 40, color: \"#4caf50\" }, // green\n { from: 40, to: 60, color: \"#ffeb3b\" }, // yellow\n { from: 60, to: 100, color: \"#f44336\" }, // red\n];\n\n// --- Default styles ---\ninterface StyleSet {\n\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\n fontFamily?: string; // optional global font family for all 3\n}\n\nconst defaultContainerSx: any = {\n width: 400,\n height: 250,\n padding: 2,\n margin: 0,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",\n borderRadius: 10,\n boxSizing: \"border-box\",\n background: \"rgb(248, 249, 250)\",\n border: \"1px solid rgba(211, 216, 220, 1)\",\n//'linear-gradient(to right, rgb(47, 99, 255), rgb(20, 110, 180))'\n fontFamily: defaultFontFamily,\n color:\"#000000\",\n overflowWrap: \"break-word\",\n label: { fontWeight: 500, color: \"#000000\", fontFamily: defaultFontFamily },\n value: { fontWeight: 700, color: \"#000000\", fontFamily: defaultFontFamily },\n unit: { fontWeight: 400, color: \"#000000\", fontFamily: defaultFontFamily },\n\n \n};\n\n// --- Circuit Breaker Config ---\nconst MAX_FAILURES = 3;\n\n/* ---------------------- Component ---------------------- */\n\nexport const LatestDataGauge: React.FC = ({\n client,\n nodeId,\n variable,\n title = \"Latest Data\",\n min = 0,\n max = 100,\n startAngleDeg = -135, // semi-circle: -90 .. 90\n endAngleDeg = 135,\n thickness, // optional\n zones = defaultZones,\n showNeedle = false,\n needleColor = \"#111\",\n needleWidth = 3,\n subtitle,\n styles = {},\n disabled = false,\n tickCount = 11,\n unit = \"Units\",\n uomOffset = -15,\n labelOffset = -7,\n onMetrics,\n valueText = ({ value: v, valueMin, valueMax }) =>\n v === undefined ? `-- / ${valueMax}` : `${v} / ${valueMax}`,\n onStyleChange,\n displayText,\n}) => {\n\n validateRequiredProps(\n \"LatestDataGauge\",\n { client, nodeId, variable },\n [\"client\", \"nodeId\", \"variable\"]\n );\n \n\n \n const [value,setValue] = useState(null)\n const [node, setNode] = useState(null); // <-- store node in state\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(null);\n\n // Build a state object to pass into the callback styles\nconst widgetState = { value, loading, error };\n\n\n// Resolve function or static style object\nconst [dynamicStyles, setDynamicStyles] = useState>({});\n\nconst baseResolvedStyles =\n typeof styles === \"function\" ? styles(widgetState) : styles || {};\n\nconst resolvedStyles = {\n container: { ...baseResolvedStyles.container, ...dynamicStyles?.container },\n label: { ...baseResolvedStyles.label, ...dynamicStyles?.label },\n value: { ...baseResolvedStyles.value, ...dynamicStyles?.value },\n unit: { ...baseResolvedStyles.unit, ...dynamicStyles?.unit },\n fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily,\n subtitle: { ...defaultSubtitleSx, ...baseResolvedStyles.subtitle, ...dynamicStyles.subtitle },\n arc: { ...defaultArcSx, ...baseResolvedStyles.arc, ...dynamicStyles.arc },\n\n};\n // --- Preventing stale closures / infinite renders ---\n \n const isFetchingRef = useRef(false);\n const failureCountRef = useRef(0);\n const mountedRef = useRef(false);\n const svgRef = useRef(null);\n\n // normalize style objects\n const containerSx = normalizeSx(resolvedStyles.container);\n const titleSx = normalizeSx(resolvedStyles.label);\n const valueTextSx = normalizeSx(resolvedStyles.value);\n const subtitleSx = normalizeSx(resolvedStyles.subtitle);\n const unitSx = normalizeSx(resolvedStyles.unit);\n const arcSx = normalizeSx(resolvedStyles.arc);\n\n\n // --- Container dimensions with TypeScript-safe default ---\n const containerDefaults: any = defaultContainerSx!;\n const width = containerSx.width ?? containerDefaults.width;\n const height = containerSx.height ?? containerDefaults.height;\n\n // convert degrees -> radians helper\n const deg2rad = (d: number) => (d * Math.PI) / 180;\n\n // clamp value into min..max safely\n const clamp = (v?: number) =>\n v === undefined ? undefined : Math.max(min, Math.min(max, v));\n\n // derived, memoized (fast)\n const metrics = useMemo(() => {\n const padding = 8; // keep inside svg\n const cx = width / 2;\n const cy = height / 2;\n // Available radius limited by width/height and padding\n const maxRadius = Math.min(width / 2, height / 2) - padding;\n // default thickness if not provided: 20% of radius\n const outerRadius = maxRadius;\n const innerRadius = Math.max(\n 6,\n outerRadius - (thickness ?? Math.round(outerRadius * 0.2))\n );\n // compute value angle\n const startRad = deg2rad(startAngleDeg);\n const endRad = deg2rad(endAngleDeg);\n // clamped value fraction\n const effectiveValue = value === undefined ? undefined : clamp(value);\n const frac =\n effectiveValue === undefined ? 0 : (effectiveValue - min) / (max - min);\n const valueAngleRad = startRad + frac * (endRad - startRad);\n const valueAngleDeg = (valueAngleRad * 180) / Math.PI;\n return {\n maxRadius,\n valueAngleDeg,\n valueAngleRad,\n startAngleDeg,\n endAngleDeg,\n innerRadius,\n outerRadius,\n cx,\n cy,\n } as GaugeMetrics;\n }, [value, min, max, startAngleDeg, endAngleDeg, width, height, thickness]);\n\n useEffect(() => {\n if (client && nodeId) {\n const anedya = (client as any)._anedya as Anedya; // retrieve wrapped instance\n const createdNode = anedya.NewNode(client, nodeId);\n setNode(createdNode);\n }\n}, [client, nodeId]);\n\n\n// --- Fetch data once safely ---\n useEffect(() => {\n\n\n mountedRef.current = true;\n if (!node) return;\n const fetchData= async()=> {\n \n if ( isFetchingRef.current|| failureCountRef.current >= MAX_FAILURES){\n\n //rate limiter ----> in client \n console.log(\"!node:\",node)\n console.log(\"isFetchingRef.current:\",isFetchingRef.current)\n console.log(\"failureCountRef.current:\",failureCountRef.current)\n return\n }; // don't try if node not ready or if an api call is being currently made already\n \n isFetchingRef.current = true;\n try {\n setLoading(true);\n setError(null);\n const res = await node.getLatestData(variable);\n\n if (!mountedRef.current) return; // <-- SAFE, stops state update if unmounted\n\n if (res.isSuccess && res.isDataAvailable) {\n\n setValue(res.data?.value);\n setError(\"\");\n // setValue(null);\n } else {\n setValue(null);\n console.error(\"error fetching data:\", res.error);\n setError(res.error.errorMessage);\n }\n failureCountRef.current = 0; // reset on success\n } catch (err: any) {\n if (!mountedRef.current) return;\n console.error(\"Error fetching latest data:\", err);\n setValue(null);\n setError(err?.message ?? \"Failed to fetch data\");\n failureCountRef.current += 1;\n \n } finally {\n if (!mountedRef.current) return;\n setLoading(false);\n isFetchingRef.current = false;\n }\n }\n fetchData();\n\n return () => {\n mountedRef.current = false;\n };\n \n }, [node, variable]);\n\n // Whenever value changes, allow user to modify styles dynamically\n useEffect(() => {\n if (typeof onStyleChange === \"function\") {\n const updated = onStyleChange(value);\n if (updated && typeof updated === \"object\") {\n setDynamicStyles(updated);\n }\n }\n }, [value]);\nconst formatted: DisplayTextResult = displayText\n ? displayText(Number(value), unit)\n : {\n text: String(value ?? \"\"),\n unitText: unit,\n position: \"right\",\n unitStyle: \"normal\",\n };\n\n\n\n\n\n // call metrics callback if provided\n useEffect(() => {\n if (onMetrics) onMetrics(metrics);\n }, [metrics, onMetrics]);\n\n // D3 draw/cleanup\n useEffect(() => {\n const svg = svgRef.current;\n if (!svg) return;\n\n // clear previous\n d3.select(svg).selectAll(\"*\").remove();\n\n const svgSel = d3.select(svg);\n\n const {\n cx,\n cy,\n outerRadius,\n innerRadius,\n valueAngleRad,\n startAngleDeg: sDeg,\n endAngleDeg: eDeg,\n } = metrics;\n\n // group container for translation and layering\n const g = svgSel.append(\"g\").attr(\"transform\", `translate(${cx}, ${cy})`); // center at 0,0 inside group\n\n // background track -> single full track from startAngle to endAngle (light gray)\n const startRad = deg2rad(sDeg);\n const endRad = deg2rad(eDeg);\n const fullArc = d3\n .arc()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius)\n .startAngle(startRad)\n .endAngle(endRad);\n\n const fullArcPathD = (fullArc as any)(undefined);\n g.append(\"path\")\n .attr(\"d\", fullArcPathD ?? \"\")\n .attr(\"fill\", arcSx.trackColor ?? \"#e6e6e6\")\n .attr(\"stroke\", \"none\");\n\n // draw zones as arcs - zones may exceed min/max so map zone percentages to angles\n // zones are in value units; convert zone from/to -> angles\n const totalAngleSpanRad = deg2rad(eDeg - sDeg);\n\n const valueToAngleRad = (v: number) => {\n const frac = (v - min) / (max - min);\n return startRad + frac * totalAngleSpanRad;\n };\n\n // sanitize zones: sort and clamp to [min, max]\n const safeZones = (zones ?? [])\n .map((z) => ({\n from: Math.max(z.from, min),\n to: Math.min(z.to, max),\n color: z.color,\n }))\n .filter((z) => z.to > z.from)\n .sort((a, b) => a.from - b.from);\n\n safeZones.forEach((z, idx) => {\n const zStart = valueToAngleRad(z.from);\n const zEnd = valueToAngleRad(z.to);\n const arcFn = d3\n .arc()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius)\n .startAngle(zStart)\n .endAngle(zEnd);\n\n const pathD = (arcFn as any)(undefined);\n g.append(\"path\")\n .attr(\"d\", pathD ?? \"\")\n .attr(\"fill\", z.color)\n .attr(\"stroke\", \"none\")\n .attr(\"opacity\", 1);\n });\n\n // Draw progress arc from startRad to valueAngleRad (if value defined)\n if (value !== undefined) {\n // don't draw if value outside range? we clamp earlier to min..max\n const progArc = d3\n .arc()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius)\n .startAngle(startRad)\n .endAngle(valueAngleRad);\n\n const progArcPathD = (progArc as any)(undefined);\n g.append(\"path\")\n .attr(\"d\", progArcPathD ?? \"\")\n .attr(\"fill\", arcSx.progressColor ?? \"rgba(255,255,255,0.15)\")\n .attr(\"stroke\", arcSx.progressStroke ?? \"#00000000\");\n }\n\n // optional needle - pointy line from center to outer radius at valueAngleRad\n if (showNeedle && value !== undefined) {\n const needleLen =\n (innerRadius + outerRadius) / 2 + (outerRadius - innerRadius) * 0.15;\n const needleG = g.append(\"g\").attr(\"class\", \"needle\");\n\n // create triangular needle or line\n const needleLine = d3.line();\n const nx = Math.cos(valueAngleRad - Math.PI / 2) * needleLen;\n const ny = Math.sin(valueAngleRad - Math.PI / 2) * needleLen;\n // Slight rotation because group center at 0,0 and d3 arc angles use 0 at 12 o'clock\n // We'll produce a simple line\n needleG\n .append(\"line\")\n .attr(\"x1\", 0)\n .attr(\"y1\", 0)\n .attr(\"x2\", nx)\n .attr(\"y2\", ny)\n .attr(\"stroke\", needleColor)\n .attr(\"stroke-width\", needleWidth)\n .attr(\"stroke-linecap\", \"round\");\n\n // small center cap\n needleG\n .append(\"circle\")\n .attr(\"cx\", 0)\n .attr(\"cy\", 0)\n .attr(\"r\", Math.max(3, Math.min(6, (outerRadius - innerRadius) * 0.25)))\n .attr(\"fill\", needleColor);\n }\n\n // center value text\n const valueString = valueText({ value, valueMin: min, valueMax: max });\n\n const valueGroup = g.append(\"g\").attr(\"class\", \"value-group\");\n\n valueGroup\n .append(\"text\")\n .attr(\"class\", \"gauge-value-text\")\n .attr(\"text-anchor\", \"middle\")\n .attr(\"y\", -((innerRadius + outerRadius) / 2) * 0.05) // slightly upward\n .style(\n \"font-size\",\n (arcSx.fontSize ?? `${Math.round(innerRadius * 0.45)}px`) as string\n )\n .style(\"font-family\", arcSx.fontFamily ?? \"Roboto, Arial, sans-serif\")\n .style(\"fill\", (valueTextSx.color as any) ?? \"#111\")\n .text(valueString);\n\n // optional subtitle below\n if (subtitle) {\n valueGroup\n .append(\"text\")\n .attr(\"class\", \"gauge-subtitle-text\")\n .attr(\"text-anchor\", \"middle\")\n .attr(\"y\", (outerRadius - innerRadius) * 0.6 + 14)\n .style(\"font-size\", (subtitleSx.fontSize ?? \"12px\") as string)\n .style(\"fill\", subtitleSx.color ?? \"#666\")\n .text(subtitle);\n }\n\n // cleanup on unmount\n return () => {\n d3.select(svg).selectAll(\"*\").remove();\n };\n }, [\n metrics,\n zones,\n value,\n min,\n max,\n showNeedle,\n needleColor,\n needleWidth,\n valueText,\n resolvedStyles, // keep redraw when style shape changes\n ]);\n\n /** Red gradient props for arcSegments */\n const redFade = useGradient(\n \"rgba(255,0,0,0)\",\n \"rgba(255,0,0,1)\",\n \"redFade-randomkey\"\n );\n\n /** Renders coloured arcs to demarcate target ranges. */\n const arcSegments = [\n // {min: 0, max:1, color: \"#148382\"}\n { min: 0, max: 0.5, color: \"rgb(181,230,29)\" },\n { min: 0.5, max: 1, color: \"orange\" },\n {\n min: 0.75,\n max: 1,\n ...redFade,\n },\n ];\n\n // --- Scaled font sizes ---\n const baseFont = Math.min(Number(width), Number(height)) * 0.15;\n\n // --- Compute font sizes dynamically if not provided by user ---\n const labelFont = (resolvedStyles?.label as any)?.fontSize ?? baseFont * 0.6;\n\n const valueFont = (resolvedStyles?.value as any)?.fontSize ?? baseFont * 1.2;\n\n const unitFont = (resolvedStyles?.unit as any)?.fontSize ?? baseFont * 0.8;\n\n // overall container style (MUI Box)\n const mergedContainer = {\n ...defaultContainerSx,\n ...containerSx,\n width,\n height,\n \n };\n // --- Font family handling ---\n const globalFontFamily = resolvedStyles?.fontFamily ?? \"Roboto\";\n const labelFontFamily = defaultContainerSx.label?.fontFamily ?? globalFontFamily;\n const valueFontFamily = defaultContainerSx.value?.fontFamily ?? globalFontFamily;\n const unitFontFamily = defaultContainerSx.label?.fontFamily ?? globalFontFamily;\n \n\n const mergedLabelSx: CSSProperties = {\n ...defaultContainerSx.label,\n fontSize: labelFont,\n ...titleSx,\n fontFamily: labelFontFamily,\n };\n const mergedValueSx: CSSProperties = {\n ...defaultContainerSx.value,\n fontSize: valueFont,\n // color: textColor,\n ...valueTextSx,\n fontFamily: valueFontFamily,\n };\n const mergedUnitSx: CSSProperties = {\n ...defaultContainerSx.unit,\n fontSize: unitFont,\n ...unitSx,\n fontFamily: unitFontFamily,\n };\n \n\n return (\n \n
\n {title && (\n

\n {title}\n

\n )}\n {loading ? (\n \n
\n \n ) : error ? (\n \n
\n \n{error}\n
\n\n \n \n \n ) : value ? (\n \n ): !value?\n \n\n
\n \n{ \"No data available\"}\n
\n\n \n\n :<>}\n \n \n );\n};\n\nexport default LatestDataGauge;\n","export default function extent(values, valueof) {\n let min;\n let max;\n if (valueof === undefined) {\n for (const value of values) {\n if (value != null) {\n if (min === undefined) {\n if (value >= value) min = max = value;\n } else {\n if (min > value) min = value;\n if (max < value) max = value;\n }\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null) {\n if (min === undefined) {\n if (value >= value) min = max = value;\n } else {\n if (min > value) min = value;\n if (max < value) max = value;\n }\n }\n }\n }\n return [min, max];\n}\n","export default function max(values, valueof) {\n let max;\n if (valueof === undefined) {\n for (const value of values) {\n if (value != null\n && (max < value || (max === undefined && value >= value))) {\n max = value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null\n && (max < value || (max === undefined && value >= value))) {\n max = value;\n }\n }\n }\n return max;\n}\n","import React from \"react\";\nimport { Gradient } from \"../components\";\n\nconst useGradient = (startColour:string, stopColour:string, id:string) => {\n return {\n color: `url(#${id})`,\n // node: disabled => (\n // \n // )\n };\n};\n\nexport default useGradient;\n"],"names":["extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","prototype","hasOwnProperty","call","__extends","TypeError","String","__","this","constructor","create","__assign","assign","t","s","i","n","arguments","length","apply","__rest","e","indexOf","getOwnPropertySymbols","propertyIsEnumerable","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","rejected","result","done","then","__generator","body","f","y","_","label","sent","trys","ops","g","Iterator","verb","Symbol","iterator","v","op","pop","push","__spreadArray","to","from","pack","ar","l","slice","concat","SuppressedError","u","R","tokenId","token","baseUrl","trim","Error","D","tokenBytes","signatureVersionBytes","signatureVersion","authorizationMode","a","TextEncoder","encode","isSuccess","error","isDataAvailable","data","count","startTime","endTime","errorMessage","reasonCode","h","namespace","key","type","size","modified","created","scope","id","A","I","totalCount","S","m","async","o","JSON","stringify","c","crypto","subtle","digest","Uint8Array","DataView","buffer","setBigUint64","BigInt","set","map","toString","padStart","join","console","log","w","r","getNodeId","getData","nodes","variable","Math","floor","limit","order","Date","now","Authorization","fetch","method","credentials","headers","json","success","keys","status","statusText","G","getLatestData","k","setKey","V","getKey","O","deleteKey","q","scanKeys","filter","orderby","offset","M","getDeviceStatus","lastContactThreshold","U","getSnapshot","time","node","E","NewConfig","NewClient","NewNode","B","GLOBAL","NODE","X","STRING","BINARY","FLOAT","BOOLEAN","globalClient","nodeRateLimiters","Map","validateRequiredProps","componentName","props","required","missing","undefined","message","defaultColorRanges","max","color","Infinity","defaultFontFamily","defaultStyles","container","width","height","padding","margin","display","flexDirection","justifyContent","alignItems","borderRadius","boxSizing","background","border","fontFamily","gap","textAlign","fontWeight","unit","normalizeSx","sx","isArray","LatestDataWidgetComponent","_a","client","nodeId","_t","title","_u","_v","styles","displayText","colorRange","colorRangeCallback","onStyleChange","_w","useState","setData","_x","loading","setLoading","_y","setError","_z","setNode","isFetchingRef","useRef","failureCountRef","mountedRef","widgetState","_0","dynamicStyles","setDynamicStyles","baseResolvedStyles","resolvedStyles","_b","formatted","Number","text","unitText","position","unitStyle","useEffect","createdNode","_anedya","current","res","_c","err_1","updated","containerSx","labelSx","valueSx","unitSx","containerDefaults","_d","baseFont","min","labelFont","_f","_e","fontSize","valueFont","_h","_g","unitFont","_k","_j","globalFontFamily","_l","labelFontFamily","_m","valueFontFamily","_o","unitFontFamily","_p","containerGap","_q","finalRange","textColor","ranges","range","find","getColorFromRange","_r","_s","mergedContainerSx","mergedLabelSx","mergedValueSx","mergedUnitSx","renderUnitText","style","_jsx","children","_jsxs","className","paddingRight","paddingLeft","boxShadow","_Fragment","LatestDataWidget","React","memo","prev","ascending","NaN","descending","bisector","compare1","compare2","delta","left","x","lo","hi","mid","zero","center","right","bisectRight","e10","sqrt","e5","e2","tickSpec","start","stop","power","log10","pow","factor","i1","i2","inc","round","tickIncrement","tickStep","reverse","identity$3","epsilon","translateX","translateY","number","scale","bandwidth","entering","__axis","axis","orient","tickArguments","tickValues","tickFormat","tickSizeInner","tickSizeOuter","tickPadding","window","devicePixelRatio","transform","context","values","ticks","domain","format","identity","spacing","range0","range1","copy","selection","path","selectAll","tick","tickExit","exit","tickEnter","enter","append","attr","line","select","merge","insert","transition","isFinite","getAttribute","parentNode","remove","each","tickSize","noop","dispatch","test","Dispatch","get","name","callback","on","typename","types","T","split","that","args","xhtml","namespaces","svg","xlink","xml","xmlns","prefix","space","local","creatorInherit","document","ownerDocument","uri","namespaceURI","documentElement","createElement","createElementNS","creatorFixed","fullname","creator","none","selector","querySelector","empty","selectorAll","querySelectorAll","arrayAll","array","matcher","matches","childMatcher","childFirst","firstElementChild","sparse","update","EnterNode","parent","datum","_next","_parent","__data__","bindIndex","group","groupLength","dataLength","bindKey","keyValue","nodeByKeyValue","keyValues","has","delete","arraylike","attrRemove","removeAttribute","attrRemoveNS","removeAttributeNS","attrConstant","setAttribute","attrConstantNS","setAttributeNS","attrFunction","attrFunctionNS","defaultView","styleRemove","removeProperty","styleConstant","priority","setProperty","styleFunction","styleValue","getPropertyValue","getComputedStyle","propertyRemove","propertyConstant","propertyFunction","classArray","string","classList","ClassList","_node","_names","classedAdd","names","list","add","classedRemove","classedTrue","classedFalse","classedFunction","textRemove","textContent","textConstant","textFunction","htmlRemove","innerHTML","htmlConstant","htmlFunction","raise","nextSibling","appendChild","lower","previousSibling","insertBefore","firstChild","constantNull","removeChild","selection_cloneShallow","clone","cloneNode","selection_cloneDeep","onRemove","__on","j","removeEventListener","listener","options","onAdd","event","contextListener","addEventListener","dispatchEvent","params","CustomEvent","createEvent","initEvent","bubbles","cancelable","detail","dispatchConstant","dispatchFunction","child","splice","contains","root","Selection","groups","parents","_groups","_parents","define","factory","extend","definition","Color","subgroups","subnode","subgroup","selectChild","match","childFind","selectChildren","childrenFilter","bind","constant","enterGroup","updateGroup","previous","i0","_enter","_exit","onenter","onupdate","onexit","groups0","groups1","m0","m1","merges","group0","group1","compareDocumentPosition","sort","compare","compareNode","sortgroups","sortgroup","getAttributeNS","property","classed","html","before","deep","typenames","parseTypenames","darker","brighter","reI","reN","reP","reHex","reRgbInteger","RegExp","reRgbPercent","reRgbaInteger","reRgbaPercent","reHslPercent","reHslaPercent","named","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen","color_formatHex","rgb","formatHex","color_formatRgb","formatRgb","toLowerCase","exec","parseInt","rgbn","Rgb","rgba","hsla","opacity","rgb_formatHex","hex","rgb_formatRgb","clampa","clampi","isNaN","Hsl","hslConvert","clamph","clampt","hsl2rgb","m2","channels","displayable","formatHex8","formatHsl","clamp","constant$1","gamma","nogamma","exponential","linear","interpolateRgb","rgbGamma","end","colorRgb","numberArray","genericArray","nb","na","date$1","setTime","interpolateNumber","object","reA","reB","source","interpolateString","am","bm","bs","bi","lastIndex","index","one","interpolate$1","date","ArrayBuffer","isView","isNumberArray","valueOf","interpolateRound","svgNode","degrees","PI","rotate","skewX","scaleX","scaleY","decompose","atan2","atan","interpolateTransform","parse","pxComma","pxParen","degParen","xa","ya","xb","yb","translate","taskHead","taskTail","interpolateTransformCss","DOMMatrix","WebKitCSSMatrix","isIdentity","interpolateTransformSvg","baseVal","consolidate","matrix","frame","timeout","interval","clockLast","clockNow","clockSkew","clock","performance","setFrame","requestAnimationFrame","setTimeout","clearNow","Timer","_call","_time","timer","delay","restart","wake","timerFlush","t0","t2","t1","sleep","nap","poke","clearTimeout","clearInterval","setInterval","elapsed","emptyOn","emptyTween","schedule","timing","schedules","__transition","self","tween","state","duration","ease","init","tweenRemove","tween0","tween1","tweenFunction","tweenValue","_id","interpolate","value1","string00","interpolate0","string1","string0","string10","attrTweenNS","attrInterpolateNS","_value","attrTween","attrInterpolate","delayFunction","delayConstant","durationFunction","durationConstant","Transition","_name","newId","selection_prototype","inherit","id0","id1","on0","on1","sit","every","onFunction","styleTween","styleNull","listener0","styleMaybeRemove","styleInterpolate","textTween","textInterpolate","removeFunction","easeConstant","easeVarying","cancel","interrupt","defaultTiming","active","pi","tau","tauEpsilon","strings","Path","digits","_x0","_y0","_x1","_y1","_append","appendRound","moveTo","closePath","lineTo","quadraticCurveTo","x1","y1","bezierCurveTo","x2","y2","arcTo","x0","y0","x21","y21","x01","y01","l01_2","abs","x20","y20","l21_2","l20_2","l21","l01","acos","t01","t21","arc","a0","a1","ccw","dx","cos","dy","sin","cw","da","rect","formatDecimalParts","toExponential","coefficient","exponent","prefixExponent","re","formatSpecifier","specifier","FormatSpecifier","fill","align","sign","symbol","comma","precision","formatRounded","formatTypes","toFixed","toLocaleString","replace","toPrecision","toUpperCase","identity$1","locale","formatPrefix","prefixes","formatLocale$1","grouping","thousands","substring","currencyPrefix","currency","currencySuffix","decimal","numerals","formatNumerals","percent","minus","nan","newFormat","suffix","formatType","maybeSuffix","valuePrefix","valueSuffix","valueNegative","out","formatTrim","charCodeAt","initRange","formatLocale","normalize","bimap","d0","d1","r0","r1","polymap","bisect","target","unknown","transformer","untransform","piecewise","output","input","interpolateValue","rescale","clamper","invert","rangeRound","continuous","precisionPrefix","precisionRound","precisionFixed","linearish","nice","prestep","maxIter","ceil","timeInterval","floori","offseti","field","millisecond","durationSecond","durationMinute","durationHour","durationDay","durationWeek","durationMonth","durationYear","second","getMilliseconds","getUTCSeconds","timeMinute","getSeconds","getMinutes","utcMinute","setUTCSeconds","getUTCMinutes","timeHour","getHours","utcHour","setUTCMinutes","getUTCHours","timeDay","setHours","setDate","getDate","getTimezoneOffset","utcDay","setUTCHours","setUTCDate","getUTCDate","unixDay","timeWeekday","getDay","timeSunday","timeMonday","timeTuesday","timeWednesday","timeThursday","timeFriday","timeSaturday","utcWeekday","getUTCDay","utcSunday","utcMonday","utcTuesday","utcWednesday","utcThursday","utcFriday","utcSaturday","timeMonth","setMonth","getMonth","getFullYear","utcMonth","setUTCMonth","getUTCMonth","getUTCFullYear","timeYear","setFullYear","utcYear","setUTCFullYear","timeTicks","timeTickInterval","year","month","week","day","hour","minute","tickIntervals","tickInterval","ticker","localDate","H","L","utcDate","UTC","newDate","timeFormat","pads","numberRe","percentRe","requoteRe","pad","requote","formatRe","formatLookup","parseWeekdayNumberSunday","parseWeekdayNumberMonday","parseWeekNumberSunday","parseWeekNumberISO","parseWeekNumberMonday","W","parseFullYear","parseYear","parseZone","Z","parseQuarter","parseMonthNumber","parseDayOfMonth","parseDayOfYear","parseHour24","parseMinutes","parseSeconds","parseMilliseconds","parseMicroseconds","parseLiteralPercent","parseUnixTimestamp","Q","parseUnixTimestampSeconds","formatDayOfMonth","formatHour24","formatHour12","formatDayOfYear","formatMilliseconds","formatMicroseconds","formatMonthNumber","formatMinutes","formatSeconds","formatWeekdayNumberMonday","formatWeekNumberSunday","dISO","formatWeekNumberISO","formatWeekdayNumberSunday","formatWeekNumberMonday","formatYear","formatYearISO","formatFullYear","formatFullYearISO","formatZone","z","formatUTCDayOfMonth","formatUTCHour24","formatUTCHour12","formatUTCDayOfYear","formatUTCMilliseconds","getUTCMilliseconds","formatUTCMicroseconds","formatUTCMonthNumber","formatUTCMinutes","formatUTCSeconds","formatUTCWeekdayNumberMonday","dow","formatUTCWeekNumberSunday","UTCdISO","formatUTCWeekNumberISO","formatUTCWeekdayNumberSunday","formatUTCWeekNumberMonday","formatUTCYear","formatUTCYearISO","formatUTCFullYear","formatUTCFullYearISO","formatUTCZone","formatLiteralPercent","formatUnixTimestamp","formatUnixTimestampSeconds","calendar","formatMillisecond","formatSecond","formatMinute","formatHour","formatDay","formatWeek","formatMonth","timeWeek","timeSecond","locale_dateTime","dateTime","locale_date","locale_time","locale_periods","periods","locale_weekdays","days","locale_shortWeekdays","shortDays","locale_months","months","locale_shortMonths","shortMonths","periodRe","periodLookup","weekdayRe","weekdayLookup","shortWeekdayRe","shortWeekdayLookup","monthRe","monthLookup","shortMonthRe","shortMonthLookup","formats","Y","utcFormats","parses","parseSpecifier","charAt","newParse","utcFormat","utcParse","defaultLocale","halfPi","asin","withPath","shape","RangeError","arcInnerRadius","innerRadius","arcOuterRadius","outerRadius","arcStartAngle","startAngle","arcEndAngle","endAngle","arcPadAngle","padAngle","cornerTangents","rc","ox","oy","x11","y11","x10","y10","x00","y00","d2","cx0","cy0","cx1","cy1","dx0","dy0","dx1","dy1","cx","cy","cornerRadius","padRadius","a01","a11","a00","a10","da0","da1","ap","rp","rc0","rc1","p0","p1","oc","x3","y3","x32","y32","intersect","ax","ay","bx","by","kc","lc","centroid","Linear","_context","curveLinear","defined","curve","defined0","lineStart","lineEnd","point","pointX","pointY","area","x0z","y0z","areaStart","areaEnd","arealine","lineX0","lineY0","lineY1","lineX1","_line","_point","curveRadialLinear","curveRadial","Radial","_curve","radial","lineRadial$1","angle","radius","circle","draw","sqrt3","symbolTriangle","slope3","h0","h1","s0","s1","slope2","MonotoneX","monotoneX","Transform","_t0","applyX","applyY","location","invertX","invertY","rescaleX","rescaleY","formatDate","css","ref","insertAt","head","getElementsByTagName","styleSheet","cssText","createTextNode","toDateSafe","ts","tooltip","chart","strokeColor","strokeWidth","gradientColors","dotRadius","SVGBase","_super","render","PureComponent","Pointer","tail","minAngle","maxAngle","disabled","pointerLine","pointerValue","scaleLinear","valueScale","moveTooltip","getElementById","clientX","top","clientY","onMouseEnter","showTooltip","onMouseMove","onMouseLeave","InvertedTriangle","stroke","UnitOfMeasurement","offsetText","uom","pointerEvents","GaugeArc","inset","maxRatio","arcMax","minRatio","arcMin","refToRads","arcScale","arcPath","lineRadial","tickLineLong","tickLineShort","Label","tickCount","minVal","maxVal","warn","idxToRef","idxToVal","refToDeg","val","deg","getTickRef","userSelect","Gradient","stopColor","Gauge","arcSegments","labelProps","uomProps","pointerLabel","gaugeOrigin","useCallback","valueRef","useMemo","viewBox","idx","defaultArcSx","trackColor","progressColor","progressStroke","defaultSubtitleSx","defaultZones","defaultContainerSx","overflowWrap","tooltipFormatter","timestamp","hour12","tickFormatter","xTickFormat","yTickFormat","tooltipFormat","resolvedXFormatter","resolvedYFormatter","decimals","includes","formatNumber","resolvedTooltipFormatter","svgRef","tooltipNodeRef","titleSx","tooltipSx","chartSx","axisSx","anedya","req","d3.select","chartW","chartH","dates","d3.scaleTime","d3.extent","maxY","valueof","d3.max","d3.scaleLinear","safeGradient","safeStroke","safeWidth","safeDotRadius","gradient","d3\n .area","d3.curveMonotoneX","d3\n .line","dotR","requested","base","computeDotRadius","dots","tooltipDiv","tooltipDefaults","backgroundColor","innerWidth","pageX","pageY","xAxis","Intl","DateTimeFormat","defaultDateFormatter","axisDefaults","d3.axisLeft","clipId","random","startAngleDeg","endAngleDeg","thickness","zones","showNeedle","needleColor","_1","needleWidth","subtitle","_2","_3","_4","_5","_6","uomOffset","_7","labelOffset","onMetrics","_8","valueText","valueMin","valueMax","_9","setValue","_10","_11","_12","_13","valueTextSx","subtitleSx","arcSx","deg2rad","metrics","maxRadius","startRad","endRad","effectiveValue","valueAngleRad","valueAngleDeg","svgSel","sDeg","eDeg","fullArcPathD","d3\n .arc","fullArc","totalAngleSpanRad","valueToAngleRad","safeZones","forEach","zStart","zEnd","pathD","d3\n .arc","arcFn","progArcPathD","progArc","needleLen","needleG","d3.line","nx","ny","valueString","valueGroup","redFade","startColour","stopColour","useGradient","mergedContainer","_this","useGlobal","forceReinit","rateLimitMs","Anedya","config","originalNewNode","_i","limiter","lastCallTime","originalGetLatestData_1","wait_1"],"mappings":"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","x_google_ignoreList":[0,1,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,172,173]} \ No newline at end of file diff --git a/dist/index.mjs b/dist/index.mjs index 8760549d..9ee0c262 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -1,2 +1,196 @@ -import{jsxs as t,jsx as e,Fragment as n}from"react/jsx-runtime";import r,{useState as i,useRef as o,useEffect as a,PureComponent as u,useCallback as l,useMemo as s}from"react";var c=function(t,e){return c=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},c(t,e)};function f(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function n(){this.constructor=t}c(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var h=function(){return h=Object.assign||function(t){for(var e,n=1,r=arguments.length;n0&&i[i.length-1])||6!==u[0]&&2!==u[0])){o=0;continue}if(3===u[0]&&(!i||u[1]>i[0]&&u[1]{try{let r=(new TextEncoder).encode(JSON.stringify(t)),i=await crypto.subtle.digest("SHA-256",r),o=new Uint8Array(i),a=new Uint8Array(8);new DataView(a.buffer).setBigUint64(0,BigInt(n),!1);let u=new Uint8Array(o.length+a.length+e.signatureVersionBytes.length+e.tokenBytes.length);u.set(o,0),u.set(a,o.length),u.set(e.signatureVersionBytes,o.length+a.length),u.set(e.tokenBytes,o.length+a.length+e.signatureVersionBytes.length);let l=await crypto.subtle.digest("SHA-256",u);return Array.from(new Uint8Array(l)).map(t=>t.toString(16).padStart(2,"0")).join("")}catch(t){console.log(t)}},D=class{#t;#e;#n;constructor(t,e){let{baseUrl:n,tokenId:r,tokenBytes:i,signatureVersionBytes:o,signatureVersion:a,authorizationMode:u}=t;this.#t=e,this.#e=n,this.#n={tokenId:r,tokenBytes:i,signatureVersion:a,signatureVersionBytes:o,authorizationMode:u}}getNodeId(){return this.#t}async getData(t){return await(async(t,e,n,r)=>{let i=`${t}/data/getData`,o={nodes:n,variable:r.variable,from:Math.floor(r.from/1e3),to:Math.floor(r.to/1e3),limit:r.limit,order:r.order},a=Math.floor(Date.now()/1e3),u=await N(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),l=new b;try{let t=await r.json();if(l.isSuccess=t.success,l.error.errorMessage=t.error,l.error.reasonCode=t.reasonCode,l.isDataAvailable=!1,l.data=null,t.success){let e=t.data;null==e||null==e||0===Object.keys(e).length?l.isDataAvailable=!1:1===n.length?(e=e[n.toString()],l.data=e,l.isDataAvailable=!0):(l.data=e,l.isDataAvailable=!0)}return l.count=t.count,l.startTime=t.startTime,l.endTime=t.endTime,l}catch{return l.isSuccess=!1,l.error.reasonCode=r.status.toString(),l.error.errorMessage=r.statusText,l}}catch(t){throw console.error("Error during Get data request:",t),t}})(this.#e,this.#n,[this.#t],t)}async getLatestData(t){let e={variable:t};return await(async(t,e,n,r)=>{let i=`${t}/data/latest`,o={nodes:n,variable:r.variable},a=Math.floor(Date.now()/1e3),u=await N(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),l=new _;try{let t=await r.json();if(l.isSuccess=t.success,l.error.errorMessage=t.error,l.error.reasonCode=t.reasonCode,l.isDataAvailable=!1,l.data=null,t.success){let e=t.data;null==e||null==e||0===Object.keys(e).length?l.isDataAvailable=!1:1===n.length?(e=e[n.toString()],l.data=e,l.isDataAvailable=!0):(l.data=e,l.isDataAvailable=!0)}return l}catch{return l.isSuccess=!1,l.error.reasonCode=r.status.toString(),l.error.errorMessage=r.statusText,l}}catch(t){throw console.error("Error during get latest data request:",t),t}})(this.#e,this.#n,[this.#t],e)}async setKey(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/setValue`;i="node"===r.namespace.scope?n[0]:r.namespace.id;let a={namespace:{scope:r.namespace.scope,id:i},key:r.key,value:r.value,type:r.type},u=Math.floor(Date.now()/1e3),l=await N(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":l,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new M;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during set key: ",t),t}})(this.#e,this.#n,[this.#t],t)}async getKey(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/getValue`;i="node"===r.namespace.scope?n[0]:r.namespace.id;let a={namespace:{scope:r.namespace.scope,id:i},key:r.key},u=Math.floor(Date.now()/1e3),l=await N(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":l,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new S;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.namespace=t.namespace,r.key=t.key,r.value=t.value,r.type=t.type,r.size=t.size,r.modified=t.modified,r.created=t.created,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during get key request: ",t),t}})(this.#e,this.#n,[this.#t],t)}async deleteKey(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/delete`;i="node"===r.namespace.scope?n[0]:r.namespace.id;let a={namespace:{scope:r.namespace.scope,id:i},key:r.key},u=Math.floor(Date.now()/1e3),l=await N(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":l,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new A;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during fetch operation:",t),t}})(this.#e,this.#n,[this.#t],t)}async scanKeys(t){return await(async(t,e,n,r)=>{let i,o=`${t}/valuestore/scan`;i="node"===r.filter.namespace.scope?n[0]:r.filter.namespace.id;let a={filter:{namespace:{scope:r.filter.namespace.scope,id:i}},orderby:r.orderby,order:r.order,limit:r.limit,offset:r.offset},u=Math.floor(Date.now()/1e3),l=await N(a,e,u);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":u.toString(),"X-Anedya-Signature":l,"Content-Type":"application/json"},n=await fetch(o,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(a)}),r=new T;try{let t=await n.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.count=t.count,r.totalCount=t.totalCount,r.data=t.data,r.next=t.next,r}catch{return r.isSuccess=!1,r.error.errorMessage=n.statusText,r.error.reasonCode=n.status.toString(),r}}catch(t){throw console.error("Error during scan vs operation: ",t),t}})(this.#e,this.#n,[this.#t],t)}async getDeviceStatus(t){return await(async(t,e,n,r)=>{let i=`${t}/health/status`,o={nodes:n,lastContactThreshold:r},a=Math.floor(Date.now()/1e3),u=await N(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),l=new k;try{let t=await r.json();return l.isSuccess=t.success,l.error.errorMessage=t.error,l.error.reasonCode=t.reasonCode,l.isSuccess&&(1===n.length?l.data=t.data[n[0]]:l.data=t.data),l}catch{return l.isSuccess=!1,l.error.errorMessage=r.statusText,l.error.reasonCode=r.status.toString(),l}}catch(t){throw console.error("Error during fetch operation:",t),t}})(this.#e,this.#n,[this.#t],t)}async getSnapshot(t){return await(async(t,e,n,r)=>{let i=`${t}/data/snapshot`,o={nodes:n,time:r?.time,variable:r?.variable},a=Math.floor(Date.now()/1e3),u=await N(o,e,a);try{let t={Authorization:e.authorizationMode,"x-Anedya-SignatureVersion":e.signatureVersion,"X-Anedya-Tokenid":e.tokenId,"X-Anedya-Timestamp":a.toString(),"X-Anedya-Signature":u,"Content-Type":"application/json"},r=await fetch(i,{method:"POST",credentials:"same-origin",headers:t,body:JSON.stringify(o)}),l=new C;try{let t=await r.json();return l.isSuccess=t.success,l.error.errorMessage=t.error,l.error.reasonCode=t.reasonCode,l.isSuccess&&(1===n.length?l.data=t.data.filter(t=>t.node===n[0]):l.data=t.data,l.count=t.count),l}catch{return l.isSuccess=!1,l.error.errorMessage=r.statusText,l.error.reasonCode=r.status.toString(),l}}catch(t){throw console.error("Error during fetch operation:",t),t}})(this.#e,this.#n,[this.#t],t)}},F=class{NewConfig(t,e){return new x(t,e)}NewClient(t){return new w(t)}NewNode(t,e){return new D(t,e)}},$=((m=$||{}).GLOBAL="global",m.NODE="node",m),E=((v=E||{}).STRING="string",v.BINARY="binary",v.FLOAT="float",v.BOOLEAN="boolean",v),U=null,z=new Map;function j(t,e,n){var r,i,o,a=this,u=null!==(r=null==n?void 0:n.useGlobal)&&void 0!==r&&r,l=null!==(i=null==n?void 0:n.forceReinit)&&void 0!==i&&i,s=null!==(o=null==n?void 0:n.rateLimitMs)&&void 0!==o?o:100;if(u&&U&&!l)return U;var c=new F,f=c.NewConfig(t,e),h=c.NewClient(f),d=c.NewNode.bind(c);return c.NewNode=function(){for(var t=[],e=0;e=3)return console.log("!node:",K),console.log("isFetchingRef.current:",et.current),console.log("failureCountRef.current:",nt.current),[2];et.current=!0,i.label=1;case 1:return i.trys.push([1,3,4,5]),W(!0),Z(null),[4,K.getLatestData(C)];case 2:return t=i.sent(),rt.current?(t.isSuccess&&t.isDataAvailable?(X(null===(n=t.data)||void 0===n?void 0:n.value),Z("")):(X(null),console.error("error fetching data:",t.error),Z(t.error.errorMessage)),nt.current=0,[3,5]):[2];case 3:return e=i.sent(),rt.current?(console.error("Error fetching latest data:",e),X(null),Z(null!==(r=null==e?void 0:e.message)&&void 0!==r?r:"Failed to fetch data"),nt.current+=1,[3,5]):[2];case 4:return rt.current?(W(!1),et.current=!1,[7]):[2];case 5:return[2]}})}),function(){rt.current=!1}}},[K,C]),a(function(){if("function"==typeof P){var t=P(H);t&&"object"==typeof t&&ut(t)}},[H]);var ft=L(null==st?void 0:st.container),ht=L(null==st?void 0:st.label),dt=L(null==st?void 0:st.value),pt=L(null==st?void 0:st.unit),gt=Y.container,yt=null!==(l=ft.width)&&void 0!==l?l:gt.width,vt=null!==(s=ft.height)&&void 0!==s?s:gt.height,mt=.15*Math.min(Number(yt),Number(vt)),xt=null!==(f=null===(c=null==st?void 0:st.label)||void 0===c?void 0:c.fontSize)&&void 0!==f?f:.6*mt,wt=null!==(y=null===(d=null==st?void 0:st.value)||void 0===d?void 0:d.fontSize)&&void 0!==y?y:3*mt,bt=null!==(m=null===(v=null==st?void 0:st.unit)||void 0===v?void 0:v.fontSize)&&void 0!==m?m:.8*mt,_t=null!==(x=null==st?void 0:st.fontFamily)&&void 0!==x?x:"Roboto",Mt=null!==(w=ht.fontFamily)&&void 0!==w?w:_t,St=null!==(b=dt.fontFamily)&&void 0!==b?b:_t,At=null!==(_=pt.fontFamily)&&void 0!==_?_:_t,Tt=null!==(M=ft.gap)&&void 0!==M?M:.2*mt,kt=null!=j?j:O,Ct=function(t,e){var n;void 0===e&&(e=O);var r=e.find(function(e){return t<=e.max});return null!==(n=null==r?void 0:r.color)&&void 0!==n?n:"#333"}(null!==(S=Number(H))&&void 0!==S?S:0,kt);R&&(Ct=R(null!==(A=Number(H))&&void 0!==A?A:0,Ct));var Nt=h(h(h({},Y.container),ft),{gap:Tt}),Dt=h(h(h(h({},Y.label),{fontSize:xt}),ht),{fontFamily:Mt}),Ft=h(h(h(h({},Y.value),{fontSize:wt,color:Ct}),dt),{fontFamily:St}),$t=h(h(h(h({},Y.unit),{fontSize:bt}),pt),{fontFamily:At}),Et=function(t,n){switch(n){case"superscript":return e("sup",{children:t});case"subscript":return e("sub",{children:t});default:return e("span",{children:t})}};return t("div",{style:h({},Nt),children:[D&&e("h2",{style:Dt,children:D}),B?e("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",height:"100%"},children:e("div",{className:"spinner",style:{width:.3*Math.min(Number(yt),Number(vt)),height:.3*Math.min(Number(yt),Number(vt))}})}):G?e("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:e("div",{style:{background:"rgba(255, 0, 0, 0.15)",border:"1px solid rgba(255, 0, 0, 0.6)",boxShadow:"rgba(149, 157, 165, 0.2) 0px 8px 24px",color:"rgba(255, 0, 0, 0.6)",textAlign:"center",borderRadius:"5px",padding:"5px"},children:G})}):H?e(n,{children:t("div",{style:h(h({},Ft),{display:"flex",flexDirection:"top"===ct.position||"bottom"===ct.position?"column":"row",alignItems:"center",justifyContent:"center",gap:4}),children:[ct.unitText&&"left"===ct.position&&e("div",{style:$t,children:Et(ct.unitText,ct.unitStyle)}),e("div",{children:ct.text}),ct.unitText&&"right"===ct.position&&e("div",{style:$t,children:Et(ct.unitText,ct.unitStyle)}),ct.unitText&&"top"===ct.position&&e("div",{style:h(h({},$t),{order:-1}),children:Et(ct.unitText,ct.unitStyle)}),ct.unitText&&"bottom"===ct.position&&e("div",{style:h(h({},$t),{order:1}),children:Et(ct.unitText,ct.unitStyle)})]})}):e("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:e("div",{style:{color:"#757575",textAlign:"center",borderRadius:"5px",padding:"5px"},children:"No data available"})})]})},V=r.memo(function(t){var r=t.client,i=t.nodeId,o=t.variable,a=t.title,u=t.unit,l=t.styles,s=void 0===l?{}:l,c=t.colorRange,f=t.colorRangeCallback,h=t.displayText,d=t.onStyleChange;return e(n,{children:e(P,{displayText:h,client:r,nodeId:i,variable:o,title:a,unit:u,styles:s,colorRange:c,colorRangeCallback:f,onStyleChange:d})})},function(t,e){return JSON.stringify(t)===JSON.stringify(e)});function H(t,e){return null==t||null==e?NaN:te?1:t>=e?0:NaN}function X(t,e){return null==t||null==e?NaN:et?1:e>=t?0:NaN}function q(t){let e,n,r;function i(t,r,i=0,o=t.length){if(i>>1;n(t[e],r)<0?i=e+1:o=e}while(iH(t(e),n),r=(e,n)=>t(e)-n):(e=t===H||t===X?t:B,n=t,r=t),{left:i,center:function(t,e,n=0,o=t.length){const a=i(t,e,n,o-1);return a>n&&r(t[a-1],e)>-r(t[a],e)?a-1:a},right:function(t,r,i=0,o=t.length){if(i>>1;n(t[e],r)<=0?i=e+1:o=e}while(i=J?10:o>=G?5:o>=Z?2:1;let u,l,s;return i<0?(s=Math.pow(10,-i)/a,u=Math.round(t*s),l=Math.round(e*s),u/se&&--l,s=-s):(s=Math.pow(10,i)*a,u=Math.round(t/s),l=Math.round(e/s),u*se&&--l),l+t(e)}function at(t,e){return e=Math.max(0,t.bandwidth()-2*e)/2,t.round()&&(e=Math.round(e)),n=>+t(n)+e}function ut(){return!this.__axis}function lt(t,e){var n=[],r=null,i=null,o=6,a=6,u=3,l="undefined"!=typeof window&&window.devicePixelRatio>1?0:.5,s=1===t||4===t?-1:1,c=4===t||2===t?"x":"y",f=1===t||3===t?rt:it;function h(h){var d=null==r?e.ticks?e.ticks.apply(e,n):e.domain():r,p=null==i?e.tickFormat?e.tickFormat.apply(e,n):et:i,g=Math.max(o,0)+u,y=e.range(),v=+y[0]+l,m=+y[y.length-1]+l,x=(e.bandwidth?at:ot)(e.copy(),l),w=h.selection?h.selection():h,b=w.selectAll(".domain").data([null]),_=w.selectAll(".tick").data(d,e).order(),M=_.exit(),S=_.enter().append("g").attr("class","tick"),A=_.select("line"),T=_.select("text");b=b.merge(b.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),_=_.merge(S),A=A.merge(S.append("line").attr("stroke","currentColor").attr(c+"2",s*o)),T=T.merge(S.append("text").attr("fill","currentColor").attr(c,s*g).attr("dy",1===t?"0em":3===t?"0.71em":"0.32em")),h!==w&&(b=b.transition(h),_=_.transition(h),A=A.transition(h),T=T.transition(h),M=M.transition(h).attr("opacity",nt).attr("transform",function(t){return isFinite(t=x(t))?f(t+l):this.getAttribute("transform")}),S.attr("opacity",nt).attr("transform",function(t){var e=this.parentNode.__axis;return f((e&&isFinite(e=e(t))?e:x(t))+l)})),M.remove(),b.attr("d",4===t||2===t?a?"M"+s*a+","+v+"H"+l+"V"+m+"H"+s*a:"M"+l+","+v+"V"+m:a?"M"+v+","+s*a+"V"+l+"H"+m+"V"+s*a:"M"+v+","+l+"H"+m),_.attr("opacity",1).attr("transform",function(t){return f(x(t)+l)}),A.attr(c+"2",s*o),T.attr(c,s*g).text(p),w.filter(ut).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",2===t?"start":4===t?"end":"middle"),w.each(function(){this.__axis=x})}return h.scale=function(t){return arguments.length?(e=t,h):e},h.ticks=function(){return n=Array.from(arguments),h},h.tickArguments=function(t){return arguments.length?(n=null==t?[]:Array.from(t),h):n.slice()},h.tickValues=function(t){return arguments.length?(r=null==t?null:Array.from(t),h):r&&r.slice()},h.tickFormat=function(t){return arguments.length?(i=t,h):i},h.tickSize=function(t){return arguments.length?(o=a=+t,h):o},h.tickSizeInner=function(t){return arguments.length?(o=+t,h):o},h.tickSizeOuter=function(t){return arguments.length?(a=+t,h):a},h.tickPadding=function(t){return arguments.length?(u=+t,h):u},h.offset=function(t){return arguments.length?(l=+t,h):l},h}var st={value:()=>{}};function ct(){for(var t,e=0,n=arguments.length,r={};e=0&&(e=t.slice(n+1),t=t.slice(0,n)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}})),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=e&&"function"!=typeof e)throw new Error("invalid callback: "+e);for(;++a0)for(var n,r,i=new Array(n),o=0;o=0&&"xmlns"!==(e=t.slice(0,n))&&(t=t.slice(n+1)),gt.hasOwnProperty(e)?{space:gt[e],local:t}:t}function vt(t){return function(){var e=this.ownerDocument,n=this.namespaceURI;return n===pt&&e.documentElement.namespaceURI===pt?e.createElement(t):e.createElementNS(n,t)}}function mt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function xt(t){var e=yt(t);return(e.local?mt:vt)(e)}function wt(){}function bt(t){return null==t?wt:function(){return this.querySelector(t)}}function _t(){return[]}function Mt(t){return null==t?_t:function(){return this.querySelectorAll(t)}}function St(t){return function(){return function(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}(t.apply(this,arguments))}}function At(t){return function(){return this.matches(t)}}function Tt(t){return function(e){return e.matches(t)}}var kt=Array.prototype.find;function Ct(){return this.firstElementChild}var Nt=Array.prototype.filter;function Dt(){return Array.from(this.children)}function Ft(t){return new Array(t.length)}function $t(t,e){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=e}function Et(t,e,n,r,i,o){for(var a,u=0,l=e.length,s=o.length;ue?1:t>=e?0:NaN}function Ot(t){return function(){this.removeAttribute(t)}}function Rt(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Yt(t,e){return function(){this.setAttribute(t,e)}}function Lt(t,e){return function(){this.setAttributeNS(t.space,t.local,e)}}function Pt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttribute(t):this.setAttribute(t,n)}}function Vt(t,e){return function(){var n=e.apply(this,arguments);null==n?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,n)}}function Ht(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function Xt(t){return function(){this.style.removeProperty(t)}}function qt(t,e,n){return function(){this.style.setProperty(t,e,n)}}function Bt(t,e,n){return function(){var r=e.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,n)}}function Wt(t,e){return t.style.getPropertyValue(e)||Ht(t).getComputedStyle(t,null).getPropertyValue(e)}function Jt(t){return function(){delete this[t]}}function Gt(t,e){return function(){this[t]=e}}function Zt(t,e){return function(){var n=e.apply(this,arguments);null==n?delete this[t]:this[t]=n}}function Qt(t){return t.trim().split(/^|\s+/)}function Kt(t){return t.classList||new te(t)}function te(t){this._node=t,this._names=Qt(t.getAttribute("class")||"")}function ee(t,e){for(var n=Kt(t),r=-1,i=e.length;++r=0&&(this._names.splice(e,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Me=[null];function Se(t,e){this._groups=t,this._parents=e}function Ae(){return new Se([[document.documentElement]],Me)}function Te(t){return"string"==typeof t?new Se([[document.querySelector(t)]],[document.documentElement]):new Se([[t]],Me)}function ke(t,e,n){t.prototype=e.prototype=n,n.constructor=t}function Ce(t,e){var n=Object.create(t.prototype);for(var r in e)n[r]=e[r];return n}function Ne(){}Se.prototype=Ae.prototype={constructor:Se,select:function(t){"function"!=typeof t&&(t=bt(t));for(var e=this._groups,n=e.length,r=new Array(n),i=0;i=w&&(w=x+1);!(m=y[w])&&++w=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function e(e,n){return e&&n?t(e.__data__,n.__data__):!e-!n}t||(t=It);for(var n=this._groups,r=n.length,i=new Array(r),o=0;o1?this.each((null==e?Xt:"function"==typeof e?Bt:qt)(t,e,null==n?"":n)):Wt(this.node(),t)},property:function(t,e){return arguments.length>1?this.each((null==e?Jt:"function"==typeof e?Zt:Gt)(t,e)):this.node()[t]},classed:function(t,e){var n=Qt(t+"");if(arguments.length<2){for(var r=Kt(this.node()),i=-1,o=n.length;++i=0&&(e=t.slice(n+1),t=t.slice(0,n)),{type:t,name:e}})}(t+""),a=o.length;if(!(arguments.length<2)){for(u=e?xe:me,r=0;r>8&15|e>>4&240,e>>4&15|240&e,(15&e)<<4|15&e,1):8===n?Be(e>>24&255,e>>16&255,e>>8&255,(255&e)/255):4===n?Be(e>>12&15|e>>8&240,e>>8&15|e>>4&240,e>>4&15|240&e,((15&e)<<4|15&e)/255):null):(e=je.exec(t))?new Je(e[1],e[2],e[3],1):(e=Ie.exec(t))?new Je(255*e[1]/100,255*e[2]/100,255*e[3]/100,1):(e=Oe.exec(t))?Be(e[1],e[2],e[3],e[4]):(e=Re.exec(t))?Be(255*e[1]/100,255*e[2]/100,255*e[3]/100,e[4]):(e=Ye.exec(t))?en(e[1],e[2]/100,e[3]/100,1):(e=Le.exec(t))?en(e[1],e[2]/100,e[3]/100,e[4]):Pe.hasOwnProperty(t)?qe(Pe[t]):"transparent"===t?new Je(NaN,NaN,NaN,0):null}function qe(t){return new Je(t>>16&255,t>>8&255,255&t,1)}function Be(t,e,n,r){return r<=0&&(t=e=n=NaN),new Je(t,e,n,r)}function We(t,e,n,r){return 1===arguments.length?((i=t)instanceof Ne||(i=Xe(i)),i?new Je((i=i.rgb()).r,i.g,i.b,i.opacity):new Je):new Je(t,e,n,null==r?1:r);var i}function Je(t,e,n,r){this.r=+t,this.g=+e,this.b=+n,this.opacity=+r}function Ge(){return`#${tn(this.r)}${tn(this.g)}${tn(this.b)}`}function Ze(){const t=Qe(this.opacity);return`${1===t?"rgb(":"rgba("}${Ke(this.r)}, ${Ke(this.g)}, ${Ke(this.b)}${1===t?")":`, ${t})`}`}function Qe(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function Ke(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function tn(t){return((t=Ke(t))<16?"0":"")+t.toString(16)}function en(t,e,n,r){return r<=0?t=e=n=NaN:n<=0||n>=1?t=e=NaN:e<=0&&(t=NaN),new rn(t,e,n,r)}function nn(t){if(t instanceof rn)return new rn(t.h,t.s,t.l,t.opacity);if(t instanceof Ne||(t=Xe(t)),!t)return new rn;if(t instanceof rn)return t;var e=(t=t.rgb()).r/255,n=t.g/255,r=t.b/255,i=Math.min(e,n,r),o=Math.max(e,n,r),a=NaN,u=o-i,l=(o+i)/2;return u?(a=e===o?(n-r)/u+6*(n0&&l<1?0:a,new rn(a,u,l,t.opacity)}function rn(t,e,n,r){this.h=+t,this.s=+e,this.l=+n,this.opacity=+r}function on(t){return(t=(t||0)%360)<0?t+360:t}function an(t){return Math.max(0,Math.min(1,t||0))}function un(t,e,n){return 255*(t<60?e+(n-e)*t/60:t<180?n:t<240?e+(n-e)*(240-t)/60:e)}ke(Ne,Xe,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:Ve,formatHex:Ve,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return nn(this).formatHsl()},formatRgb:He,toString:He}),ke(Je,We,Ce(Ne,{brighter(t){return t=null==t?Fe:Math.pow(Fe,t),new Je(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?De:Math.pow(De,t),new Je(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new Je(Ke(this.r),Ke(this.g),Ke(this.b),Qe(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Ge,formatHex:Ge,formatHex8:function(){return`#${tn(this.r)}${tn(this.g)}${tn(this.b)}${tn(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:Ze,toString:Ze})),ke(rn,function(t,e,n,r){return 1===arguments.length?nn(t):new rn(t,e,n,null==r?1:r)},Ce(Ne,{brighter(t){return t=null==t?Fe:Math.pow(Fe,t),new rn(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?De:Math.pow(De,t),new rn(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),e=isNaN(t)||isNaN(this.s)?0:this.s,n=this.l,r=n+(n<.5?n:1-n)*e,i=2*n-r;return new Je(un(t>=240?t-240:t+120,i,r),un(t,i,r),un(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new rn(on(this.h),an(this.s),an(this.l),Qe(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=Qe(this.opacity);return`${1===t?"hsl(":"hsla("}${on(this.h)}, ${100*an(this.s)}%, ${100*an(this.l)}%${1===t?")":`, ${t})`}`}}));var ln=t=>()=>t;function sn(t){return 1===(t=+t)?cn:function(e,n){return n-e?function(t,e,n){return t=Math.pow(t,n),e=Math.pow(e,n)-t,n=1/n,function(r){return Math.pow(t+r*e,n)}}(e,n,t):ln(isNaN(e)?n:e)}}function cn(t,e){var n=e-t;return n?function(t,e){return function(n){return t+n*e}}(t,n):ln(isNaN(t)?e:t)}var fn=function t(e){var n=sn(e);function r(t,e){var r=n((t=We(t)).r,(e=We(e)).r),i=n(t.g,e.g),o=n(t.b,e.b),a=cn(t.opacity,e.opacity);return function(e){return t.r=r(e),t.g=i(e),t.b=o(e),t.opacity=a(e),t+""}}return r.gamma=t,r}(1);function hn(t,e){e||(e=[]);var n,r=t?Math.min(e.length,t.length):0,i=e.slice();return function(o){for(n=0;no&&(i=e.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(n=n[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,l.push({i:a,x:gn(n,r)})),o=mn.lastIndex;return o180?e+=360:e-t>180&&(t+=360),o.push({i:n.push(i(n)+"rotate(",null,r)-2,x:gn(t,e)})):e&&n.push(i(n)+"rotate("+e+r)}(o.rotate,a.rotate,u,l),function(t,e,n,o){t!==e?o.push({i:n.push(i(n)+"skewX(",null,r)-2,x:gn(t,e)}):e&&n.push(i(n)+"skewX("+e+r)}(o.skewX,a.skewX,u,l),function(t,e,n,r,o,a){if(t!==n||e!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:gn(t,n)},{i:u-2,x:gn(e,r)})}else 1===n&&1===r||o.push(i(o)+"scale("+n+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,l),o=a=null,function(t){for(var e,n=-1,r=l.length;++n=0&&e._call.call(void 0,t),e=e._next;--Fn}()}finally{Fn=0,function(){var t,e,n=kn,r=1/0;for(;n;)n._call?(r>n._time&&(r=n._time),t=n,n=n._next):(e=n._next,n._next=null,n=t?t._next=e:kn=e);Cn=t,Xn(r)}(),zn=0}}function Hn(){var t=In.now(),e=t-Un;e>1e3&&(jn-=e,Un=t)}function Xn(t){Fn||($n&&($n=clearTimeout($n)),t-zn>24?(t<1/0&&($n=setTimeout(Vn,t-In.now()-jn)),En&&(En=clearInterval(En))):(En||(Un=In.now(),En=setInterval(Hn,1e3)),Fn=1,On(Vn)))}function qn(t,e,n){var r=new Ln;return e=null==e?0:+e,r.restart(n=>{r.stop(),t(n+e)},e,n),r}Ln.prototype=Pn.prototype={constructor:Ln,restart:function(t,e,n){if("function"!=typeof t)throw new TypeError("callback is not a function");n=(null==n?Rn():+n)+(null==e?0:+e),this._next||Cn===this||(Cn?Cn._next=this:kn=this,Cn=this),this._call=t,this._time=n,Xn()},stop:function(){this._call&&(this._call=null,this._time=1/0,Xn())}};var Bn=ct("start","end","cancel","interrupt"),Wn=[];function Jn(t,e,n,r,i,o){var a=t.__transition;if(a){if(n in a)return}else t.__transition={};!function(t,e,n){var r,i=t.__transition;function o(t){n.state=1,n.timer.restart(a,n.delay,n.time),n.delay<=t&&a(t-n.delay)}function a(o){var s,c,f,h;if(1!==n.state)return l();for(s in i)if((h=i[s]).name===n.name){if(3===h.state)return qn(a);4===h.state?(h.state=6,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[s]):+s0)throw new Error("too late; already scheduled");return n}function Zn(t,e){var n=Qn(t,e);if(n.state>3)throw new Error("too late; already running");return n}function Qn(t,e){var n=t.__transition;if(!n||!(n=n[e]))throw new Error("transition not found");return n}function Kn(t,e){var n,r;return function(){var i=Zn(this,t),o=i.tween;if(o!==n)for(var a=0,u=(r=n=o).length;a=0&&(t=t.slice(0,e)),!t||"start"===t})}(e)?Gn:Zn;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(e,n),a.on=i}}(n,t,e))},attr:function(t,e){var n=yt(t),r="transform"===n?Dn:nr;return this.attrTween(t,"function"==typeof e?(n.local?lr:ur)(n,r,er(this,"attr."+t,e)):null==e?(n.local?ir:rr)(n):(n.local?ar:or)(n,r,e))},attrTween:function(t,e){var n="attr."+t;if(arguments.length<2)return(n=this.tween(n))&&n._value;if(null==e)return this.tween(n,null);if("function"!=typeof e)throw new Error;var r=yt(t);return this.tween(n,(r.local?sr:cr)(r,e))},style:function(t,e,n){var r="transform"==(t+="")?Nn:nr;return null==e?this.styleTween(t,function(t,e){var n,r,i;return function(){var o=Wt(this,t),a=(this.style.removeProperty(t),Wt(this,t));return o===a?null:o===n&&a===r?i:i=e(n=o,r=a)}}(t,r)).on("end.style."+t,yr(t)):"function"==typeof e?this.styleTween(t,function(t,e,n){var r,i,o;return function(){var a=Wt(this,t),u=n(this),l=u+"";return null==u&&(this.style.removeProperty(t),l=u=Wt(this,t)),a===l?null:a===r&&l===i?o:(i=l,o=e(r=a,u))}}(t,r,er(this,"style."+t,e))).each(function(t,e){var n,r,i,o,a="style."+e,u="end."+a;return function(){var l=Zn(this,t),s=l.on,c=null==l.value[a]?o||(o=yr(e)):void 0;s===n&&i===c||(r=(n=s).copy()).on(u,i=c),l.on=r}}(this._id,t)):this.styleTween(t,function(t,e,n){var r,i,o=n+"";return function(){var a=Wt(this,t);return a===o?null:a===r?i:i=e(r=a,n)}}(t,r,e),n).on("end.style."+t,null)},styleTween:function(t,e,n){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==e)return this.tween(r,null);if("function"!=typeof e)throw new Error;return this.tween(r,function(t,e,n){var r,i;function o(){var o=e.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,e,n){return function(r){this.style.setProperty(t,e.call(this,r),n)}}(t,o,n)),r}return o._value=e,o}(t,e,null==n?"":n))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var e=t(this);this.textContent=null==e?"":e}}(er(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var e="text";if(arguments.length<1)return(e=this.tween(e))&&e._value;if(null==t)return this.tween(e,null);if("function"!=typeof t)throw new Error;return this.tween(e,function(t){var e,n;function r(){var r=t.apply(this,arguments);return r!==n&&(e=(n=r)&&function(t){return function(e){this.textContent=t.call(this,e)}}(r)),e}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var e=this.parentNode;for(var n in this.__transition)if(+n!==t)return;e&&e.removeChild(this)}}(this._id))},tween:function(t,e){var n=this._id;if(t+="",arguments.length<2){for(var r,i=Qn(this.node(),n).tween,o=0,a=i.length;o2&&n.state<5,n.state=6,n.timer.stop(),n.on.call(r?"interrupt":"cancel",t,t.__data__,n.index,n.group),delete o[i]):a=!1;a&&delete t.__transition}}(this,t)})},Ae.prototype.transition=function(t){var e,n;t instanceof mr?(e=t._id,t=t._name):(e=xr(),(n=br).time=Rn(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o=0))throw new Error(`invalid digits: ${t}`);if(e>15)return kr;const n=10**e;return function(t){this._+=t[0];for(let e=1,r=t.length;eAr)if(Math.abs(c*u-l*s)>Ar&&i){let h=n-o,d=r-a,p=u*u+l*l,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(f),m=i*Math.tan((Mr-Math.acos((p+f-g)/(2*y*v)))/2),x=m/v,w=m/y;Math.abs(x-1)>Ar&&this._append`L${t+x*s},${e+x*c}`,this._append`A${i},${i},0,0,${+(c*h>s*d)},${this._x1=t+w*u},${this._y1=e+w*l}`}else this._append`L${this._x1=t},${this._y1=e}`;else;}arc(t,e,n,r,i,o){if(t=+t,e=+e,o=!!o,(n=+n)<0)throw new Error(`negative radius: ${n}`);let a=n*Math.cos(r),u=n*Math.sin(r),l=t+a,s=e+u,c=1^o,f=o?r-i:i-r;null===this._x1?this._append`M${l},${s}`:(Math.abs(this._x1-l)>Ar||Math.abs(this._y1-s)>Ar)&&this._append`L${l},${s}`,n&&(f<0&&(f=f%Sr+Sr),f>Tr?this._append`A${n},${n},0,1,${c},${t-a},${e-u}A${n},${n},0,1,${c},${this._x1=l},${this._y1=s}`:f>Ar&&this._append`A${n},${n},0,${+(f>=Mr)},${c},${this._x1=t+n*Math.cos(i)},${this._y1=e+n*Math.sin(i)}`)}rect(t,e,n,r){this._append`M${this._x0=this._x1=+t},${this._y0=this._y1=+e}h${n=+n}v${+r}h${-n}Z`}toString(){return this._}}function Nr(t,e){if((n=(t=e?t.toExponential(e-1):t.toExponential()).indexOf("e"))<0)return null;var n,r=t.slice(0,n);return[r.length>1?r[0]+r.slice(2):r,+t.slice(n+1)]}function Dr(t){return(t=Nr(Math.abs(t)))?t[1]:NaN}var Fr,$r=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Er(t){if(!(e=$r.exec(t)))throw new Error("invalid format: "+t);var e;return new Ur({fill:e[1],align:e[2],sign:e[3],symbol:e[4],zero:e[5],width:e[6],comma:e[7],precision:e[8]&&e[8].slice(1),trim:e[9],type:e[10]})}function Ur(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function zr(t,e){var n=Nr(t,e);if(!n)return t+"";var r=n[0],i=n[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Er.prototype=Ur.prototype,Ur.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var jr={"%":(t,e)=>(100*t).toFixed(e),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,e)=>t.toExponential(e),f:(t,e)=>t.toFixed(e),g:(t,e)=>t.toPrecision(e),o:t=>Math.round(t).toString(8),p:(t,e)=>zr(100*t,e),r:zr,s:function(t,e){var n=Nr(t,e);if(!n)return t+"";var r=n[0],i=n[1],o=i-(Fr=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Nr(t,Math.max(0,e+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function Ir(t){return t}var Or,Rr,Yr,Lr=Array.prototype.map,Pr=["y","z","a","f","p","n","Β΅","m","","k","M","G","T","P","E","Z","Y"];function Vr(t){var e,n,r=void 0===t.grouping||void 0===t.thousands?Ir:(e=Lr.call(t.grouping,Number),n=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=e[0],l=0;i>0&&u>0&&(l+u+1>r&&(u=Math.max(1,r-l)),o.push(t.substring(i-=u,i+u)),!((l+=u+1)>r));)u=e[a=(a+1)%e.length];return o.reverse().join(n)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?Ir:function(t){return function(e){return e.replace(/[0-9]/g,function(e){return t[+e]})}}(Lr.call(t.numerals,String)),l=void 0===t.percent?"%":t.percent+"",s=void 0===t.minus?"βˆ’":t.minus+"",c=void 0===t.nan?"NaN":t.nan+"";function f(t){var e=(t=Er(t)).fill,n=t.align,f=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,m=t.type;"n"===m?(g=!0,m="g"):jr[m]||(void 0===y&&(y=12),v=!0,m="g"),(d||"0"===e&&"="===n)&&(d=!0,e="0",n="=");var x="$"===h?i:"#"===h&&/[boxX]/.test(m)?"0"+m.toLowerCase():"",w="$"===h?o:/[%p]/.test(m)?l:"",b=jr[m],_=/[defgprs%]/.test(m);function M(t){var i,o,l,h=x,M=w;if("c"===m)M=b(t)+M,t="";else{var S=(t=+t)<0||1/t<0;if(t=isNaN(t)?c:b(Math.abs(t),y),v&&(t=function(t){t:for(var e,n=t.length,r=1,i=-1;r0&&(i=0)}return i>0?t.slice(0,i)+t.slice(e+1):t}(t)),S&&0===+t&&"+"!==f&&(S=!1),h=(S?"("===f?f:s:"-"===f||"("===f?"":f)+h,M=("s"===m?Pr[8+Fr/3]:"")+M+(S&&"("===f?")":""),_)for(i=-1,o=t.length;++i(l=t.charCodeAt(i))||l>57){M=(46===l?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var A=h.length+t.length+M.length,T=A>1)+h+t+M+T.slice(A);break;default:t=T+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(m)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:f,formatPrefix:function(t,e){var n=f(((t=Er(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Dr(e)/3))),i=Math.pow(10,-r),o=Pr[8+r/3];return function(t){return n(i*t)+o}}}}function Hr(t,e){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(e).domain(t)}return this}function Xr(t){return+t}Or=Vr({thousands:",",grouping:[3],currency:["$",""]}),Rr=Or.format,Yr=Or.formatPrefix;var qr=[0,1];function Br(t){return t}function Wr(t,e){return(e-=t=+t)?function(n){return(n-t)/e}:function(t){return function(){return t}}(isNaN(e)?NaN:.5)}function Jr(t,e,n){var r=t[0],i=t[1],o=e[0],a=e[1];return ie&&(n=t,t=e,e=n),function(n){return Math.max(t,Math.min(e,n))}}(a[0],a[t-1])),r=t>2?Gr:Jr,i=o=null,f}function f(e){return null==e||isNaN(e=+e)?n:(i||(i=r(a.map(t),u,l)))(t(s(e)))}return f.invert=function(n){return s(e((o||(o=r(u,a.map(t),gn)))(n)))},f.domain=function(t){return arguments.length?(a=Array.from(t,Xr),c()):a.slice()},f.range=function(t){return arguments.length?(u=Array.from(t),c()):u.slice()},f.rangeRound=function(t){return u=Array.from(t),l=bn,c()},f.clamp=function(t){return arguments.length?(s=!!t||Br,c()):s!==Br},f.interpolate=function(t){return arguments.length?(l=t,c()):l},f.unknown=function(t){return arguments.length?(n=t,f):n},function(n,r){return t=n,e=r,c()}}function Kr(){return Qr()(Br,Br)}function ti(t,e,n,r){var i,o=tt(t,e,n);switch((r=Er(null==r?",f":r)).type){case"s":var a=Math.max(Math.abs(t),Math.abs(e));return null!=r.precision||isNaN(i=function(t,e){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Dr(e)/3)))-Dr(Math.abs(t)))}(o,a))||(r.precision=i),Yr(r,a);case"":case"e":case"g":case"p":case"r":null!=r.precision||isNaN(i=function(t,e){return t=Math.abs(t),e=Math.abs(e)-t,Math.max(0,Dr(e)-Dr(t))+1}(o,Math.max(Math.abs(t),Math.abs(e))))||(r.precision=i-("e"===r.type));break;case"f":case"%":null!=r.precision||isNaN(i=function(t){return Math.max(0,-Dr(Math.abs(t)))}(o))||(r.precision=i-2*("%"===r.type))}return Rr(r)}function ei(t){var e=t.domain;return t.ticks=function(t){var n=e();return function(t,e,n){if(!((n=+n)>0))return[];if((t=+t)===(e=+e))return[t];const r=e=i))return[];const u=o-i+1,l=new Array(u);if(r)if(a<0)for(let t=0;t0;){if((i=K(l,s,n))===r)return o[a]=l,o[u]=s,e(o);if(i>0)l=Math.floor(l/i)*i,s=Math.ceil(s/i)*i;else{if(!(i<0))break;l=Math.ceil(l*i)/i,s=Math.floor(s*i)/i}r=i}return t},t}function ni(){var t=Kr();return t.copy=function(){return Zr(t,ni())},Hr.apply(t,arguments),ei(t)}const ri=new Date,ii=new Date;function oi(t,e,n,r){function i(e){return t(e=0===arguments.length?new Date:new Date(+e)),e}return i.floor=e=>(t(e=new Date(+e)),e),i.ceil=n=>(t(n=new Date(n-1)),e(n,1),t(n),n),i.round=t=>{const e=i(t),n=i.ceil(t);return t-e(e(t=new Date(+t),null==n?1:Math.floor(n)),t),i.range=(n,r,o)=>{const a=[];if(n=i.ceil(n),o=null==o?1:Math.floor(o),!(n0))return a;let u;do{a.push(u=new Date(+n)),e(n,o),t(n)}while(uoi(e=>{if(e>=e)for(;t(e),!n(e);)e.setTime(e-1)},(t,r)=>{if(t>=t)if(r<0)for(;++r<=0;)for(;e(t,-1),!n(t););else for(;--r>=0;)for(;e(t,1),!n(t););}),n&&(i.count=(e,r)=>(ri.setTime(+e),ii.setTime(+r),t(ri),t(ii),Math.floor(n(ri,ii))),i.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?e=>r(e)%t===0:e=>i.count(0,e)%t===0):i:null)),i}const ai=oi(()=>{},(t,e)=>{t.setTime(+t+e)},(t,e)=>e-t);ai.every=t=>(t=Math.floor(t),isFinite(t)&&t>0?t>1?oi(e=>{e.setTime(Math.floor(e/t)*t)},(e,n)=>{e.setTime(+e+n*t)},(e,n)=>(n-e)/t):ai:null),ai.range;const ui=1e3,li=6e4,si=36e5,ci=864e5,fi=6048e5,hi=2592e6,di=31536e6,pi=oi(t=>{t.setTime(t-t.getMilliseconds())},(t,e)=>{t.setTime(+t+e*ui)},(t,e)=>(e-t)/ui,t=>t.getUTCSeconds());pi.range;const gi=oi(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*ui)},(t,e)=>{t.setTime(+t+e*li)},(t,e)=>(e-t)/li,t=>t.getMinutes());gi.range;const yi=oi(t=>{t.setUTCSeconds(0,0)},(t,e)=>{t.setTime(+t+e*li)},(t,e)=>(e-t)/li,t=>t.getUTCMinutes());yi.range;const vi=oi(t=>{t.setTime(t-t.getMilliseconds()-t.getSeconds()*ui-t.getMinutes()*li)},(t,e)=>{t.setTime(+t+e*si)},(t,e)=>(e-t)/si,t=>t.getHours());vi.range;const mi=oi(t=>{t.setUTCMinutes(0,0,0)},(t,e)=>{t.setTime(+t+e*si)},(t,e)=>(e-t)/si,t=>t.getUTCHours());mi.range;const xi=oi(t=>t.setHours(0,0,0,0),(t,e)=>t.setDate(t.getDate()+e),(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*li)/ci,t=>t.getDate()-1);xi.range;const wi=oi(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/ci,t=>t.getUTCDate()-1);wi.range;const bi=oi(t=>{t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+e)},(t,e)=>(e-t)/ci,t=>Math.floor(t/ci));function _i(t){return oi(e=>{e.setDate(e.getDate()-(e.getDay()+7-t)%7),e.setHours(0,0,0,0)},(t,e)=>{t.setDate(t.getDate()+7*e)},(t,e)=>(e-t-(e.getTimezoneOffset()-t.getTimezoneOffset())*li)/fi)}bi.range;const Mi=_i(0),Si=_i(1),Ai=_i(2),Ti=_i(3),ki=_i(4),Ci=_i(5),Ni=_i(6);function Di(t){return oi(e=>{e.setUTCDate(e.getUTCDate()-(e.getUTCDay()+7-t)%7),e.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCDate(t.getUTCDate()+7*e)},(t,e)=>(e-t)/fi)}Mi.range,Si.range,Ai.range,Ti.range,ki.range,Ci.range,Ni.range;const Fi=Di(0),$i=Di(1),Ei=Di(2),Ui=Di(3),zi=Di(4),ji=Di(5),Ii=Di(6);Fi.range,$i.range,Ei.range,Ui.range,zi.range,ji.range,Ii.range;const Oi=oi(t=>{t.setDate(1),t.setHours(0,0,0,0)},(t,e)=>{t.setMonth(t.getMonth()+e)},(t,e)=>e.getMonth()-t.getMonth()+12*(e.getFullYear()-t.getFullYear()),t=>t.getMonth());Oi.range;const Ri=oi(t=>{t.setUTCDate(1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCMonth(t.getUTCMonth()+e)},(t,e)=>e.getUTCMonth()-t.getUTCMonth()+12*(e.getUTCFullYear()-t.getUTCFullYear()),t=>t.getUTCMonth());Ri.range;const Yi=oi(t=>{t.setMonth(0,1),t.setHours(0,0,0,0)},(t,e)=>{t.setFullYear(t.getFullYear()+e)},(t,e)=>e.getFullYear()-t.getFullYear(),t=>t.getFullYear());Yi.every=t=>isFinite(t=Math.floor(t))&&t>0?oi(e=>{e.setFullYear(Math.floor(e.getFullYear()/t)*t),e.setMonth(0,1),e.setHours(0,0,0,0)},(e,n)=>{e.setFullYear(e.getFullYear()+n*t)}):null,Yi.range;const Li=oi(t=>{t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)},(t,e)=>{t.setUTCFullYear(t.getUTCFullYear()+e)},(t,e)=>e.getUTCFullYear()-t.getUTCFullYear(),t=>t.getUTCFullYear());Li.every=t=>isFinite(t=Math.floor(t))&&t>0?oi(e=>{e.setUTCFullYear(Math.floor(e.getUTCFullYear()/t)*t),e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0)},(e,n)=>{e.setUTCFullYear(e.getUTCFullYear()+n*t)}):null,Li.range;const[Pi,Vi]=function(t,e,n,r,i,o){const a=[[pi,1,ui],[pi,5,5e3],[pi,15,15e3],[pi,30,3e4],[o,1,li],[o,5,3e5],[o,15,9e5],[o,30,18e5],[i,1,si],[i,3,108e5],[i,6,216e5],[i,12,432e5],[r,1,ci],[r,2,1728e5],[n,1,fi],[e,1,hi],[e,3,7776e6],[t,1,di]];function u(e,n,r){const i=Math.abs(n-e)/r,o=q(([,,t])=>t).right(a,i);if(o===a.length)return t.every(tt(e/di,n/di,r));if(0===o)return ai.every(Math.max(tt(e,n,r),1));const[u,l]=a[i/a[o-1][2][t.toLowerCase(),e]))}function ro(t,e,n){var r=Gi.exec(e.slice(n,n+1));return r?(t.w=+r[0],n+r[0].length):-1}function io(t,e,n){var r=Gi.exec(e.slice(n,n+1));return r?(t.u=+r[0],n+r[0].length):-1}function oo(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.U=+r[0],n+r[0].length):-1}function ao(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.V=+r[0],n+r[0].length):-1}function uo(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.W=+r[0],n+r[0].length):-1}function lo(t,e,n){var r=Gi.exec(e.slice(n,n+4));return r?(t.y=+r[0],n+r[0].length):-1}function so(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),n+r[0].length):-1}function co(t,e,n){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(e.slice(n,n+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),n+r[0].length):-1}function fo(t,e,n){var r=Gi.exec(e.slice(n,n+1));return r?(t.q=3*r[0]-3,n+r[0].length):-1}function ho(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.m=r[0]-1,n+r[0].length):-1}function po(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.d=+r[0],n+r[0].length):-1}function go(t,e,n){var r=Gi.exec(e.slice(n,n+3));return r?(t.m=0,t.d=+r[0],n+r[0].length):-1}function yo(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.H=+r[0],n+r[0].length):-1}function vo(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.M=+r[0],n+r[0].length):-1}function mo(t,e,n){var r=Gi.exec(e.slice(n,n+2));return r?(t.S=+r[0],n+r[0].length):-1}function xo(t,e,n){var r=Gi.exec(e.slice(n,n+3));return r?(t.L=+r[0],n+r[0].length):-1}function wo(t,e,n){var r=Gi.exec(e.slice(n,n+6));return r?(t.L=Math.floor(r[0]/1e3),n+r[0].length):-1}function bo(t,e,n){var r=Zi.exec(e.slice(n,n+1));return r?n+r[0].length:-1}function _o(t,e,n){var r=Gi.exec(e.slice(n));return r?(t.Q=+r[0],n+r[0].length):-1}function Mo(t,e,n){var r=Gi.exec(e.slice(n));return r?(t.s=+r[0],n+r[0].length):-1}function So(t,e){return Ki(t.getDate(),e,2)}function Ao(t,e){return Ki(t.getHours(),e,2)}function To(t,e){return Ki(t.getHours()%12||12,e,2)}function ko(t,e){return Ki(1+xi.count(Yi(t),t),e,3)}function Co(t,e){return Ki(t.getMilliseconds(),e,3)}function No(t,e){return Co(t,e)+"000"}function Do(t,e){return Ki(t.getMonth()+1,e,2)}function Fo(t,e){return Ki(t.getMinutes(),e,2)}function $o(t,e){return Ki(t.getSeconds(),e,2)}function Eo(t){var e=t.getDay();return 0===e?7:e}function Uo(t,e){return Ki(Mi.count(Yi(t)-1,t),e,2)}function zo(t){var e=t.getDay();return e>=4||0===e?ki(t):ki.ceil(t)}function jo(t,e){return t=zo(t),Ki(ki.count(Yi(t),t)+(4===Yi(t).getDay()),e,2)}function Io(t){return t.getDay()}function Oo(t,e){return Ki(Si.count(Yi(t)-1,t),e,2)}function Ro(t,e){return Ki(t.getFullYear()%100,e,2)}function Yo(t,e){return Ki((t=zo(t)).getFullYear()%100,e,2)}function Lo(t,e){return Ki(t.getFullYear()%1e4,e,4)}function Po(t,e){var n=t.getDay();return Ki((t=n>=4||0===n?ki(t):ki.ceil(t)).getFullYear()%1e4,e,4)}function Vo(t){var e=t.getTimezoneOffset();return(e>0?"-":(e*=-1,"+"))+Ki(e/60|0,"0",2)+Ki(e%60,"0",2)}function Ho(t,e){return Ki(t.getUTCDate(),e,2)}function Xo(t,e){return Ki(t.getUTCHours(),e,2)}function qo(t,e){return Ki(t.getUTCHours()%12||12,e,2)}function Bo(t,e){return Ki(1+wi.count(Li(t),t),e,3)}function Wo(t,e){return Ki(t.getUTCMilliseconds(),e,3)}function Jo(t,e){return Wo(t,e)+"000"}function Go(t,e){return Ki(t.getUTCMonth()+1,e,2)}function Zo(t,e){return Ki(t.getUTCMinutes(),e,2)}function Qo(t,e){return Ki(t.getUTCSeconds(),e,2)}function Ko(t){var e=t.getUTCDay();return 0===e?7:e}function ta(t,e){return Ki(Fi.count(Li(t)-1,t),e,2)}function ea(t){var e=t.getUTCDay();return e>=4||0===e?zi(t):zi.ceil(t)}function na(t,e){return t=ea(t),Ki(zi.count(Li(t),t)+(4===Li(t).getUTCDay()),e,2)}function ra(t){return t.getUTCDay()}function ia(t,e){return Ki($i.count(Li(t)-1,t),e,2)}function oa(t,e){return Ki(t.getUTCFullYear()%100,e,2)}function aa(t,e){return Ki((t=ea(t)).getUTCFullYear()%100,e,2)}function ua(t,e){return Ki(t.getUTCFullYear()%1e4,e,4)}function la(t,e){var n=t.getUTCDay();return Ki((t=n>=4||0===n?zi(t):zi.ceil(t)).getUTCFullYear()%1e4,e,4)}function sa(){return"+0000"}function ca(){return"%"}function fa(t){return+t}function ha(t){return Math.floor(+t/1e3)}function da(t){return new Date(t)}function pa(t){return t instanceof Date?+t:+new Date(+t)}function ga(t,e,n,r,i,o,a,u,l,s){var c=Kr(),f=c.invert,h=c.domain,d=s(".%L"),p=s(":%S"),g=s("%I:%M"),y=s("%I %p"),v=s("%a %d"),m=s("%b %d"),x=s("%B"),w=s("%Y");function b(t){return(l(t)=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:fa,s:ha,S:$o,u:Eo,U:Uo,V:jo,w:Io,W:Oo,x:null,X:null,y:Ro,Y:Lo,Z:Vo,"%":ca},w={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return l[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:Ho,e:Ho,f:Jo,g:aa,G:la,H:Xo,I:qo,j:Bo,L:Wo,m:Go,M:Zo,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:fa,s:ha,S:Qo,u:Ko,U:ta,V:na,w:ra,W:ia,x:null,X:null,y:oa,Y:ua,Z:sa,"%":ca},b={a:function(t,e,n){var r=d.exec(e.slice(n));return r?(t.w=p.get(r[0].toLowerCase()),n+r[0].length):-1},A:function(t,e,n){var r=f.exec(e.slice(n));return r?(t.w=h.get(r[0].toLowerCase()),n+r[0].length):-1},b:function(t,e,n){var r=v.exec(e.slice(n));return r?(t.m=m.get(r[0].toLowerCase()),n+r[0].length):-1},B:function(t,e,n){var r=g.exec(e.slice(n));return r?(t.m=y.get(r[0].toLowerCase()),n+r[0].length):-1},c:function(t,n,r){return S(t,e,n,r)},d:po,e:po,f:wo,g:so,G:lo,H:yo,I:yo,j:go,L:xo,m:ho,M:vo,p:function(t,e,n){var r=s.exec(e.slice(n));return r?(t.p=c.get(r[0].toLowerCase()),n+r[0].length):-1},q:fo,Q:_o,s:Mo,S:mo,u:io,U:oo,V:ao,w:ro,W:uo,x:function(t,e,r){return S(t,n,e,r)},X:function(t,e,n){return S(t,r,e,n)},y:so,Y:lo,Z:co,"%":bo};function _(t,e){return function(n){var r,i,o,a=[],u=-1,l=0,s=t.length;for(n instanceof Date||(n=new Date(+n));++u53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=Xi(qi(o.y,0,1))).getUTCDay(),r=i>4||0===i?$i.ceil(r):$i(r),r=wi.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=Hi(qi(o.y,0,1))).getDay(),r=i>4||0===i?Si.ceil(r):Si(r),r=xi.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?Xi(qi(o.y,0,1)).getUTCDay():Hi(qi(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,Xi(o)):Hi(o)}}function S(t,e,n,r){for(var i,o,a=0,u=e.length,l=n.length;a=l)return-1;if(37===(i=e.charCodeAt(a++))){if(i=e.charAt(a++),!(o=b[i in Ji?e.charAt(a++):i])||(r=o(t,n,r))<0)return-1}else if(i!=n.charCodeAt(r++))return-1}return r}return x.x=_(n,x),x.X=_(r,x),x.c=_(e,x),w.x=_(n,w),w.X=_(r,w),w.c=_(e,w),{format:function(t){var e=_(t+="",x);return e.toString=function(){return t},e},parse:function(t){var e=M(t+="",!1);return e.toString=function(){return t},e},utcFormat:function(t){var e=_(t+="",w);return e.toString=function(){return t},e},utcParse:function(t){var e=M(t+="",!0);return e.toString=function(){return t},e}}}(t),Wi=Bi.format,Bi.parse,Bi.utcFormat,Bi.utcParse}({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});const ma=Math.abs,xa=Math.atan2,wa=Math.cos,ba=Math.max,_a=Math.min,Ma=Math.sin,Sa=Math.sqrt,Aa=1e-12,Ta=Math.PI,ka=Ta/2,Ca=2*Ta;function Na(t){return t>=1?ka:t<=-1?-ka:Math.asin(t)}function Da(t){let e=3;return t.digits=function(n){if(!arguments.length)return e;if(null==n)e=null;else{const t=Math.floor(n);if(!(t>=0))throw new RangeError(`invalid digits: ${n}`);e=t}return t},()=>new Cr(e)}function Fa(t){return t.innerRadius}function $a(t){return t.outerRadius}function Ea(t){return t.startAngle}function Ua(t){return t.endAngle}function za(t){return t&&t.padAngle}function ja(t,e,n,r,i,o,a){var u=t-n,l=e-r,s=(a?o:-o)/Sa(u*u+l*l),c=s*l,f=-s*u,h=t+c,d=e+f,p=n+c,g=r+f,y=(h+p)/2,v=(d+g)/2,m=p-h,x=g-d,w=m*m+x*x,b=i-o,_=h*g-p*d,M=(x<0?-1:1)*Sa(ba(0,b*b*w-_*_)),S=(_*x-m*M)/w,A=(-_*m-x*M)/w,T=(_*x+m*M)/w,k=(-_*m+x*M)/w,C=S-y,N=A-v,D=T-y,F=k-v;return C*C+N*N>D*D+F*F&&(S=T,A=k),{cx:S,cy:A,x01:-c,y01:-f,x11:S*(i/b-1),y11:A*(i/b-1)}}function Ia(){var t=Fa,e=$a,n=va(0),r=null,i=Ea,o=Ua,a=za,u=null,l=Da(s);function s(){var s,c,f=+t.apply(this,arguments),h=+e.apply(this,arguments),d=i.apply(this,arguments)-ka,p=o.apply(this,arguments)-ka,g=ma(p-d),y=p>d;if(u||(u=s=l()),hAa)if(g>Ca-Aa)u.moveTo(h*wa(d),h*Ma(d)),u.arc(0,0,h,d,p,!y),f>Aa&&(u.moveTo(f*wa(p),f*Ma(p)),u.arc(0,0,f,p,d,y));else{var v,m,x=d,w=p,b=d,_=p,M=g,S=g,A=a.apply(this,arguments)/2,T=A>Aa&&(r?+r.apply(this,arguments):Sa(f*f+h*h)),k=_a(ma(h-f)/2,+n.apply(this,arguments)),C=k,N=k;if(T>Aa){var D=Na(T/f*Ma(A)),F=Na(T/h*Ma(A));(M-=2*D)>Aa?(b+=D*=y?1:-1,_-=D):(M=0,b=_=(d+p)/2),(S-=2*F)>Aa?(x+=F*=y?1:-1,w-=F):(S=0,x=w=(d+p)/2)}var $=h*wa(x),E=h*Ma(x),U=f*wa(_),z=f*Ma(_);if(k>Aa){var j,I=h*wa(w),O=h*Ma(w),R=f*wa(b),Y=f*Ma(b);if(g1?0:t<-1?Ta:Math.acos(t)}((L*V+P*H)/(Sa(L*L+P*P)*Sa(V*V+H*H)))/2),q=Sa(j[0]*j[0]+j[1]*j[1]);C=_a(k,(f-q)/(X-1)),N=_a(k,(h-q)/(X+1))}else C=N=0}S>Aa?N>Aa?(v=ja(R,Y,$,E,h,N,y),m=ja(I,O,U,z,h,N,y),u.moveTo(v.cx+v.x01,v.cy+v.y01),NAa&&M>Aa?C>Aa?(v=ja(U,z,I,O,f,-C,y),m=ja($,E,R,Y,f,-C,y),u.lineTo(v.cx+v.x01,v.cy+v.y01),C=f;--h)u.point(v[h],m[h]);u.lineEnd(),u.areaEnd()}y&&(v[c]=+t(d,c,s),m[c]=+e(d,c,s),u.point(r?+r(d,c,s):v[c],n?+n(d,c,s):m[c]))}if(p)return u=null,p+""||null}function c(){return Va().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?La:va(+t),e="function"==typeof e?e:va(void 0===e?0:+e),n="function"==typeof n?n:void 0===n?Pa:va(+n),s.x=function(e){return arguments.length?(t="function"==typeof e?e:va(+e),r=null,s):t},s.x0=function(e){return arguments.length?(t="function"==typeof e?e:va(+e),s):t},s.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:va(+t),s):r},s.y=function(t){return arguments.length?(e="function"==typeof t?t:va(+t),n=null,s):e},s.y0=function(t){return arguments.length?(e="function"==typeof t?t:va(+t),s):e},s.y1=function(t){return arguments.length?(n=null==t?null:"function"==typeof t?t:va(+t),s):n},s.lineX0=s.lineY0=function(){return c().x(t).y(e)},s.lineY1=function(){return c().x(t).y(n)},s.lineX1=function(){return c().x(r).y(e)},s.defined=function(t){return arguments.length?(i="function"==typeof t?t:va(!!t),s):i},s.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),s):a},s.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),s):o},s}Ra.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){switch(t=+t,e=+e,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;default:this._context.lineTo(t,e)}}};var Xa=Ba(Ya);function qa(t){this._curve=t}function Ba(t){function e(e){return new qa(t(e))}return e._curve=t,e}function Wa(){return t=Va().curve(Xa),e=t.curve,t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?e(Ba(t)):e()._curve},t;var t,e}qa.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,e){this._curve.point(e*Math.sin(t),e*-Math.cos(t))}};var Ja={draw(t,e){const n=Sa(e/Ta);t.moveTo(n,0),t.arc(0,0,n,0,Ca)}};const Ga=Sa(3);var Za={draw(t,e){const n=-Sa(e/(3*Ga));t.moveTo(0,2*n),t.lineTo(-Ga*n,-n),t.lineTo(Ga*n,-n),t.closePath()}};function Qa(t,e){let n=null,r=Da(i);function i(){let i;if(n||(n=i=r()),t.apply(this,arguments).draw(n,+e.apply(this,arguments)),i)return n=null,i+""||null}return t="function"==typeof t?t:va(t||Ja),e="function"==typeof e?e:va(void 0===e?64:+e),i.type=function(e){return arguments.length?(t="function"==typeof e?e:va(e),i):t},i.size=function(t){return arguments.length?(e="function"==typeof t?t:va(+t),i):e},i.context=function(t){return arguments.length?(n=null==t?null:t,i):n},i}function Ka(t){return t<0?-1:1}function tu(t,e,n){var r=t._x1-t._x0,i=e-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(n-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(Ka(o)+Ka(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function eu(t,e){var n=t._x1-t._x0;return n?(3*(t._y1-t._y0)/n-e)/2:e}function nu(t,e,n){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*e,o-u,a-u*n,o,a)}function ru(t){this._context=t}function iu(t){return new ru(t)}function ou(t,e,n){this.k=t,this.x=e,this.y=n}ru.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:nu(this,this._t0,eu(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,e){var n=NaN;if(e=+e,(t=+t)!==this._x1||e!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,e):this._context.moveTo(t,e);break;case 1:this._point=2;break;case 2:this._point=3,nu(this,eu(this,n=tu(this,t,e)),n);break;default:nu(this,this._t0,n=tu(this,t,e))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=e,this._t0=n}}},Object.create(ru.prototype).point=function(t,e){ru.prototype.point.call(this,e,t)},ou.prototype={constructor:ou,scale:function(t){return 1===t?this:new ou(this.k*t,this.x,this.y)},translate:function(t,e){return 0===t&0===e?this:new ou(this.k,this.x+this.k*t,this.y+this.k*e)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}},ou.prototype;function au(t,e){return e.replace("YYYY",String(t.getFullYear())).replace("MM",String(t.getMonth()+1).padStart(2,"0")).replace("DD",String(t.getDate()).padStart(2,"0")).replace("HH",String(t.getHours()).padStart(2,"0")).replace("hh",String(t.getHours()%12||12).padStart(2,"0")).replace("mm",String(t.getMinutes()).padStart(2,"0")).replace("ss",String(t.getSeconds()).padStart(2,"0"))}!function(t,e){void 0===e&&(e={});var n=e.insertAt;if("undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===n&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=t:i.appendChild(document.createTextNode(t))}}(".pointer-wrapper {\n position: relative;\n}\n\n.pointer-wrapper:hover::after {\n content: attr(data-tooltip);\n position: absolute;\n left: 50%;\n top: -10px;\n transform: translate(-50%, -100%);\n background: black;\n color: white;\n padding: 4px 8px;\n font-size: 12px;\n border-radius: 4px;\n white-space: nowrap;\n pointer-events: none;\n}\n#gauge-tooltip {\n background: rgba(0, 0, 0, 0.8);\n color: white;\n padding: 6px 10px;\n border-radius: 6px;\n font-size: 13px;\n transition: opacity 0.2s ease, transform 0.2s ease;\n transform: translateY(-5px);\n white-space: nowrap;\n}\n\n.spinner {\n border: 4px solid rgba(0, 0, 0, 0.1);\n border-top-color: rgba(0, 0, 0, 0.7);\n border-radius: 50%;\n animation: spin 0.8s linear infinite;\n}\n\n@keyframes spin {\n to {\n transform: rotate(360deg);\n }\n}");var uu=function(t){return t?Array.isArray(t)?Object.assign.apply(Object,y([{}],t,!1)):"function"==typeof t?t({}):t:{}},lu=function(t){return t<1e12?new Date(1e3*t):new Date(t)},su="Roboto, sans-serif",cu={container:{width:400,height:250,padding:2,margin:0,display:"flex",flexDirection:"column",justifyContent:"flex-start",alignItems:"center",borderRadius:10,boxSizing:"border-box",gap:0,background:"rgb(248, 249, 250)",border:"1px solid rgba(211, 216, 220, 1)",textAlign:"center",fontFamily:su},title:{fontWeight:600,color:"rgba(0,0,0,0.75)",fontFamily:su},tooltip:{background:"rgba(0,0,0,0.75)",color:"#ffffff",borderRadius:"6px",padding:"6px 10px",fontSize:"12px"},axis:{color:"#666",fontSize:"11px",fontFamily:su},chart:{strokeColor:"#1e88e5",strokeWidth:2,gradientColors:["#1e88e5","#90caf9"],dotRadius:4}},fu=function(n){var r,u,l,s,c,f,d,y,v,m,x,w,b=n.client,_=n.nodeId,M=n.variable,S=n.from,A=n.to,T=n.limit,k=void 0===T?20:T,C=n.title,N=void 0===C?"Latest Data":C,D=n.styles,F=void 0===D?{}:D,$=n.tooltipFormatter,E=void 0===$?function(t){return"".concat(new Date(new Date(t.timestamp<1e12?1e3*t.timestamp:t.timestamp)).toLocaleString(void 0,{month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!0}),": ").concat(t.value)}:$,U=n.tickCount,z=void 0===U?4:U,j=n.tickFormatter,O=n.xTickFormat,R=n.yTickFormat,Y=n.tooltipFormat,L=n.onStyleChange;I("Chart Widget",{client:b,nodeId:_,variable:M,from:S,to:A},["client","nodeId","variable","from time","to time"]);var P="string"==typeof O?function(t){return au(t,O)}:O,V="string"==typeof R?function(t){return function(t,e){if(/0\.0+/.test(e)){var n=e.split(".")[1].length;return t.toFixed(n)}return e.includes("value")&&e.includes("unit")?e.replace("value",String(t)).replace("unit",""):String(t)}(t,R)}:R,H="string"==typeof Y?function(t){return"".concat(au(lu(t.timestamp),Y),": ").concat(t.value)}:Y,X=o(null),q=o(null),B=i([]),W=B[0],J=B[1],G=i(!1),Z=G[0],Q=G[1],K=i(null),tt=K[0],et=K[1],nt=i(null),rt=nt[0],it=nt[1],ot={data:W,loading:Z,error:tt},at=i({}),ut=at[0],st=at[1],ct="function"==typeof F?F(ot):F||{},ft={container:h(h({},ct.container),null==ut?void 0:ut.container),title:h(h({},ct.title),null==ut?void 0:ut.title),tooltip:h(h({},ct.tooltip),null==ut?void 0:ut.tooltip),chart:h(h({},ct.chart),null==ut?void 0:ut.chart),axis:h(h({},ct.axis),null==ut?void 0:ut.axis),fontFamily:null!==(r=null==ut?void 0:ut.fontFamily)&&void 0!==r?r:ct.fontFamily},ht=o(!1),dt=o(0),pt=o(!1),gt=uu(null==ft?void 0:ft.container),yt=uu(null==ft?void 0:ft.title),vt=uu(null==ft?void 0:ft.tooltip),mt=null!==(u=ft.chart)&&void 0!==u?u:{},xt=uu(null==ft?void 0:ft.axis),wt=cu.container,bt=null!==(l=gt.width)&&void 0!==l?l:wt.width,_t=null!==(s=gt.height)&&void 0!==s?s:wt.height,Mt=null!==(c=null==ft?void 0:ft.fontFamily)&&void 0!==c?c:"Roboto",St=null!==(f=yt.fontFamily)&&void 0!==f?f:Mt,At=.15*Math.min(Number(bt),Number(_t)),Tt=null!==(y=null===(d=null==ft?void 0:ft.title)||void 0===d?void 0:d.fontSize)&&void 0!==y?y:.6*At,kt=null!==(v=mt.strokeColor)&&void 0!==v?v:cu.chart.strokeColor,Ct=null!==(m=mt.strokeWidth)&&void 0!==m?m:cu.chart.strokeWidth,Nt=null!==(x=mt.gradientColors)&&void 0!==x?x:cu.chart.gradientColors,Dt=null!==(w=mt.dotRadius)&&void 0!==w?w:cu.chart.dotRadius;a(function(){var t;if(b&&_){var e=b._anedya,n=null===(t=null==e?void 0:e.NewNode)||void 0===t?void 0:t.call(e,b,_);it(n)}},[b,_]),a(function(){if(ht.current=!0,rt){return p(void 0,void 0,void 0,function(){var t,e,n,r;return g(this,function(i){switch(i.label){case 0:if(pt.current||dt.current>=3)return[2];pt.current=!0,i.label=1;case 1:return i.trys.push([1,3,4,5]),Q(!0),et(null),t={variable:M,from:S,to:A,limit:k,order:"asc"},[4,rt.getData(t)];case 2:return e=i.sent(),ht.current?(e.isSuccess&&e.isDataAvailable?(J(e.data),et("")):(console.error("error fetching data:",e.error),et(e.error.errorMessage)),dt.current=0,[3,5]):[2];case 3:return n=i.sent(),console.error("Error fetching chart data:",n),J([]),et(null!==(r=null==n?void 0:n.message)&&void 0!==r?r:"Failed to fetch data"),dt.current+=1,[3,5];case 4:return Q(!1),ht.current&&(pt.current=!1),[7];case 5:return[2]}})}),function(){ht.current=!1}}},[rt,M]),a(function(){var t,e,n,r,i,o,a,u,l,s,c,f;if(X.current){var h=Te(X.current);if(h.selectAll("*").remove(),W&&0!==W.length){var d=20,p=20,g=130,y=50,v=Math.max(10,bt-y-p),m=Math.max(10,_t-d-g),x=h.append("g").attr("transform","translate(".concat(y,",").concat(d,")")),w=W.map(function(t){return lu(t.timestamp)}),b=ya().domain(function(t){let e,n;for(const r of t)null!=r&&(void 0===e?r>=r&&(e=n=r):(e>r&&(e=r),n=e)&&(n=e);else{let r=-1;for(let i of t)null!=(i=e(i,++r,t))&&(n=i)&&(n=i)}return n}(W,function(t){return Number(t.value)}))&&void 0!==t?t:10),M=ni().domain([0,_]).nice().range([m,0]),S=null!=Nt?Nt:["#1e88e5","#90caf9"],A=null!=kt?kt:"#1e88e5",T=null!=Ct?Ct:2,k=null!=Dt?Dt:4,C=h.append("defs").append("linearGradient").attr("id","chartGradient").attr("x1","0%").attr("y1","0%").attr("x2","0%").attr("y2","100%");C.append("stop").attr("offset","0%").attr("stop-color",S[0]).attr("stop-opacity",.5),C.append("stop").attr("offset","100%").attr("stop-color",S[1]).attr("stop-opacity",0);var N=Ha().x(function(t){return b(lu(t.timestamp))}).y0(m).y1(function(t){return M(t.value)}).curve(iu);x.append("path").datum(W).attr("fill","url(#chartGradient)").attr("d",N);var D=Va().x(function(t){return b(lu(t.timestamp))}).y(function(t){return M(t.value)}).curve(iu);x.append("path").datum(W).attr("fill","none").attr("stroke",A).attr("stroke-width",T).attr("d",D);var F=function(t,e,n){var r=Math.max(2,.012*Math.min(t,e));return null!=n?n:Math.round(r)}(v,m,k),$=x.selectAll(".dot").data(W).enter().append("circle").attr("class","dot").attr("cx",function(t){return b(lu(t.timestamp))}).attr("cy",function(t){return M(t.value)}).attr("r",F).attr("fill",A).style("cursor","default"),U=q.current;U||(U=document.createElement("div"),q.current=U,document.body.appendChild(U));var j=cu.tooltip;U.style.position="absolute",U.style.pointerEvents="none",U.style.opacity="0",U.style.background=null!==(e=vt.backgroundColor)&&void 0!==e?e:j.background,U.style.color=null!==(n=vt.color)&&void 0!==n?n:j.color,U.style.borderRadius=null!==(r=vt.borderRadius)&&void 0!==r?r:j.borderRadius,U.style.padding=null!==(i=vt.padding)&&void 0!==i?i:j.padding,U.style.fontSize=null!==(o=vt.fontSize)&&void 0!==o?o:j.fontSize,U.style.transition="opacity 120ms",$.on("mouseover",function(t,e){U.style.opacity="1",U.innerHTML=H?H(e):E(e)}).on("mousemove",function(t){var e=Math.min(window.innerWidth-200,t.pageX+8),n=Math.max(8,t.pageY-36);U.style.left="".concat(e,"px"),U.style.top="".concat(n,"px")}).on("mouseout",function(){U.style.opacity="0"});var I,O=(I=b,lt(3,I)).ticks(z).tickFormat(function(t){return P?P(t):function(t){return new Intl.DateTimeFormat(void 0,{month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!0}).format(t)}(t)}),R=cu.axis;x.append("g").attr("transform","translate(0,".concat(m,")")).call(O).selectAll("text").attr("transform","rotate(-30)").style("text-anchor","end").style("font-size",null!==(a=xt.fontSize)&&void 0!==a?a:R.fontSize).style("fill",null!==(u=xt.color)&&void 0!==u?u:R.color).style("font-family",null!==(l=xt.fontFamily)&&void 0!==l?l:R.fontFamily),x.append("g").call(function(t){return lt(4,t)}(M).ticks(5).tickFormat(function(t){return V?V(t):String(t)})).selectAll("text").style("font-size",null!==(s=xt.fontSize)&&void 0!==s?s:R.fontSize).style("fill",null!==(c=xt.color)&&void 0!==c?c:R.color).style("font-family",null!==(f=xt.fontFamily)&&void 0!==f?f:R.fontFamily);var Y="clip-".concat(Math.random().toString(36).slice(2,9));return h.append("defs").append("clipPath").attr("id",Y).append("rect").attr("width",bt).attr("height",_t),h.attr("clip-path","url(#".concat(Y,")")),function(){if(q.current){try{q.current.remove()}catch(t){}q.current=null}h.selectAll("*").remove()}}}},[W,bt,_t,kt,Ct,Nt,Dt,z,j,E,xt,vt]),a(function(){if("function"==typeof L){var t=L(W);t&&"object"==typeof t&&st(t)}},[W]);var Ft=h(h({},cu.container),gt),$t=h(h(h(h({},cu.title),{fontSize:Tt}),yt),{fontFamily:St});return t("div",{style:h({},Ft),children:[N&&e("h2",{style:h({},$t),children:N}),Z?e("div",{style:{display:"flex",width:"100%",height:"100%",justifyContent:"center",alignItems:"center"},children:e("div",{className:"spinner",style:{width:.3*Math.min(Number(bt),Number(_t)),height:.3*Math.min(Number(bt),Number(_t))}})}):tt?e("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:e("div",{style:{background:"rgba(255, 0, 0, 0.15)",border:"1px solid rgba(255, 0, 0, 0.6)",boxShadow:"rgba(149, 157, 165, 0.2) 0px 8px 24px",color:"rgba(255, 0, 0, 0.6)",textAlign:"center",borderRadius:"5px",padding:"5px"},children:tt})}):0===(null==W?void 0:W.length)?e("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:e("div",{style:{color:"#757575",textAlign:"center",borderRadius:"5px",padding:"5px"},children:"No data available"})}):e("svg",{ref:X,width:bt,height:"90%"})]})},hu=function(t){function n(){return null!==t&&t.apply(this,arguments)||this}return f(n,t),n.prototype.render=function(){var t=this.props,n=t.children,r=d(t,["children"]);return e("svg",h({},r,{children:n}))},n}(u),du=function(t){function n(){return null!==t&&t.apply(this,arguments)||this}return f(n,t),n.prototype.render=function(){var t=this.props,n=t.width,r=void 0===n?12.5:n,i=t.head,o=void 0===i?95:i,a=t.tail,u=void 0===a?5:a,l=t.value,s=void 0===l?-5:l,c=t.tooltip,f=void 0===c?"":c,h=t.center,d=void 0===h?{x:125,y:135}:h,p=t.minAngle,g=t.maxAngle,y=t.disabled,v=Va()([[r/2,0],[0,-o],[-r/2,0],[0,u],[r/2,0]]),m=ni().domain([0,1]).range([p,g])(s),x=function(t){var e=document.getElementById("gauge-tooltip");e&&(e.style.left=t.clientX+10+"px",e.style.top=t.clientY-20+"px")};return e("g",{className:"pointer-wrapper","data-tooltip":f,children:e("path",{className:"gauge-pointer",d:null!=v?v:void 0,transform:"translate(".concat(d.x,", ").concat(d.y,") rotate(").concat(m,")"),fill:"#333",opacity:y?.3:void 0,style:{transition:"all 0.25s 0.25s",color:"white"},onMouseEnter:function(t){return function(t,e){var n=document.getElementById("gauge-tooltip");n&&e&&(n.textContent=e,n.style.opacity="1",n.style.transform="translateY(0px)",x(t))}(t,f)},onMouseMove:function(t){return x(t)},onMouseLeave:function(){var t=document.getElementById("gauge-tooltip");t&&(t.style.opacity="0",t.style.transform="translateY(-5px)")},children:f&&e("title",{children:f})})})},n}(u),pu=function(t){function n(){return null!==t&&t.apply(this,arguments)||this}return f(n,t),n.prototype.render=function(){var t,n=this.props,r=n.center,i=n.disabled;return e("path",{className:"gauge-target",d:null!==(t=Qa().type(Za)())&&void 0!==t?t:void 0,transform:"translate(".concat(r.x,",").concat(r.y-110,") rotate(180)"),fill:i?"#adb2ba":"#ffa500",stroke:i?"#adb2ba":"#000",strokeWidth:1,style:{transition:"all 0.25s 0.25s"}})},n}(u),gu=function(t,n){switch(n){case"superscript":return e("sup",{children:t});case"subscript":return e("sub",{children:t});default:return e("span",{children:t})}},yu=function(n){function r(){return null!==n&&n.apply(this,arguments)||this}return f(r,n),r.prototype.render=function(){var n=this.props;n.value;var r=n.disabled,i=n.center,o=n.offsetText;n.uom;var a=n.mergedValueSx,u=n.mergedUnitSx,l=n.formatted;return d(n,["value","disabled","center","offsetText","uom","mergedValueSx","mergedUnitSx","formatted"]),e("foreignObject",{x:i.x-100+o,y:i.y-40,width:200,height:80,pointerEvents:"none",opacity:r?.4:void 0,children:t("div",{style:h(h({display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",gap:4},a),{background:"transparent"}),children:[l.unitText&&"left"===l.position&&e("div",{style:u,children:gu(l.unitText,l.unitStyle)}),e("div",{style:a,children:l.text}),l.unitText&&"right"===l.position&&e("div",{style:u,children:gu(l.unitText,l.unitStyle)}),l.unitText&&"top"===l.position&&e("div",{style:h(h({},u),{order:-1}),children:gu(l.unitText,l.unitStyle)}),l.unitText&&"bottom"===l.position&&e("div",{style:h(h({},u),{order:1}),children:gu(l.unitText,l.unitStyle)})]})})},r}(u),vu=function(t){function n(){return null!==t&&t.apply(this,arguments)||this}return f(n,t),n.prototype.render=function(){var t=this.props,n=t.inset,r=void 0===n?0:n,i=t.min,o=void 0===i?0:i,a=t.max,u=void 0===a?1:a,l=t.maxAngle,s=t.minAngle,c=t.center,f=void 0===c?{x:125,y:135}:c,p=d(t,["inset","min","max","maxAngle","minAngle","center"]),g=l/180,y=Math.PI*g,v=s/180,m=Math.PI*v,x=ni().domain([0,1]).range([m,y]),w=ni().domain([0,39]).range([x(o),x(u)]),b=Wa().angle(function(t,e){return w(e)}).radius(100-r)({length:40});return e("path",h({className:"guage-arc",d:b,transform:"translate(".concat(f.x,",").concat(f.y,")"),fill:"transparent",style:{transition:"all 0.25s 0.25s"}},p))},n}(u),mu=Va().x(0).y(function(t,e){return e})(Array.from({length:35})),xu=Va().x(0).y(function(t,e){return e})(Array.from({length:12})),wu=function(n){function r(){return null!==n&&n.apply(this,arguments)||this}return f(r,n),r.prototype.render=function(){var n=this.props,r=n.disabled,i=n.center,o=n.tickCount,a=n.min,u=n.max,l=n.maxAngle,s=n.minAngle,c=n.offsetText,f=n.length,h=void 0===f?120:f,d=function(t,e,n,r,i){t%2==0&&console.warn("Ticks should be odd numbered to ensure a tick in in the middle of the gauge.");var o=ni().domain([0,t-1]).range([0,1]),a=ni().domain([0,t-1]).range([e,n]),u=ni().domain([0,1]).range([r,i]);return y([],Array(t),!0).map(function(t,e){return{index:e,val:a(e),deg:u(o(e))}})}(o,a,u,s,l);return d.map(function(n){var o,a=n.val,u=n.deg,l=n.index;return t("g",{className:"gauge-label",style:{userSelect:"none",textAlign:"center"},transform:"translate(".concat(i.x,",").concat(i.y,") rotate(").concat(u,")"),children:[e("path",{d:null!==(o=0===l||l===d.length-1?mu:xu)&&void 0!==o?o:void 0,stroke:"#344c69",strokeWidth:"1",transform:"translate(0,".concat(7.5-h,")"),style:{transition:"all .25s .25s"},opacity:r?.4:void 0}),e("text",{transform:"translate(".concat(c,",").concat(-h,")"),style:{transition:"all .25s .25s",fontSize:"85%"},opacity:r?.4:void 0,children:Number(a)})]},a)})},r}(u);!function(n){function r(){return null!==n&&n.apply(this,arguments)||this}f(r,n),r.prototype.render=function(){var n=this.props,r=n.start,i=n.end,o=n.id,a=n.disabled;return e("defs",{children:t("linearGradient",{id:o,x1:"0%",y1:"0%",x2:"0%",y2:"100%",children:[e("stop",{offset:"0%",stopColor:a?"rgba(0,0,0,0)":r}),e("stop",{offset:"100%",stopColor:a?"rgba(0,0,0,0.4)":i})]})})}}(u);var bu=function(r){var i=r.height,o=void 0===i?400:i,a=r.width,u=void 0===a?400:a,c=r.disabled,f=void 0!==c&&c,p=r.value,g=void 0===p?-1:p,y=r.min,v=void 0===y?0:y,m=r.max,x=void 0===m?100:m,w=r.maxAngle,b=void 0===w?135:w,_=r.minAngle,M=void 0===_?-135:_,S=r.tickCount,A=void 0===S?5:S,T=r.arcSegments,k=void 0===T?[{min:0,max:1,color:"skyblue"}]:T,C=r.labelProps,N=void 0===C?{offsetText:-7.5}:C,D=r.uom,F=void 0===D?"":D,$=r.uomProps,E=void 0===$?{offsetText:-10}:$,U=r.pointerLabel,z=void 0===U?"":U,j=r.mergedUnitSx,I=void 0===j?{}:j,O=r.mergedValueSx,R=void 0===O?{}:O,Y=r.formatted,L=d(r,["height","width","disabled","value","min","max","maxAngle","minAngle","tickCount","arcSegments","labelProps","uom","uomProps","pointerLabel","mergedUnitSx","mergedValueSx","formatted"]),P={x:140,y:140},V=l(ni().domain([v,x]).range([0,1]),[v,x]),H=s(function(){return V(g)},[g,V]);return e(n,{children:t(hu,h({className:"gauge",width:u||(o||250),height:o||(u||250),viewBox:"0 0 280 280",style:{transition:"all 0.25s 0.25s"}},L,{children:[e(vu,{stroke:"#344c69",strokeWidth:4,center:P,maxAngle:b,minAngle:M,opacity:f?.25:void 0}),e(wu,h({disabled:f,center:P,tickCount:A,min:v,max:x,maxAngle:b,minAngle:M},N)),k.map(function(t,n){var r=t.min,i=t.max,o=t.color;return e("g",{children:e(vu,{inset:12,min:r,max:i,stroke:o,strokeWidth:20,center:P,maxAngle:b,minAngle:M},"gauge-arcsegment-".concat(n))},"arcsegment-".concat(n))}),e(pu,{center:P,disabled:f}),e(du,{value:f?-.025:H,center:P,disabled:f,maxAngle:b,minAngle:M,tooltip:z||g}),e(yu,h({value:g,uom:F,disabled:f,center:P,mergedValueSx:R,mergedUnitSx:I,formatted:Y},E))]}))})},_u=function(t){return t?Array.isArray(t)?Object.assign.apply(Object,y([{}],t,!1)):"function"==typeof t?t({}):t:{}},Mu="Roboto, sans-serif",Su={trackColor:"#e6e6e6",progressColor:"#4caf50",progressStroke:"none",fontSize:"20px",fontFamily:Mu},Au={fontSize:"12px",color:"#666",fontFamily:Mu},Tu=[{from:0,to:40,color:"#4caf50"},{from:40,to:60,color:"#ffeb3b"},{from:60,to:100,color:"#f44336"}],ku={width:400,height:250,padding:2,margin:0,display:"flex",flexDirection:"column",justifyContent:"flex-start",alignItems:"center",borderRadius:10,boxSizing:"border-box",background:"rgb(248, 249, 250)",border:"1px solid rgba(211, 216, 220, 1)",fontFamily:Mu,color:"#000000",overflowWrap:"break-word",label:{fontWeight:500,color:"#000000",fontFamily:Mu},value:{fontWeight:700,color:"#000000",fontFamily:Mu},unit:{fontWeight:400,color:"#000000",fontFamily:Mu}},Cu=function(r){var u,l,c,f,d,y,v,m,x,w,b,_,M,S,A,T,k=r.client,C=r.nodeId,N=r.variable,D=r.title,F=void 0===D?"Latest Data":D,$=r.min,E=void 0===$?0:$,U=r.max,z=void 0===U?100:U,j=r.startAngleDeg,O=void 0===j?-135:j,R=r.endAngleDeg,Y=void 0===R?135:R,L=r.thickness,P=r.zones,V=void 0===P?Tu:P,H=r.showNeedle,X=void 0!==H&&H,q=r.needleColor,B=void 0===q?"#111":q,W=r.needleWidth,J=void 0===W?3:W,G=r.subtitle,Z=r.styles,Q=void 0===Z?{}:Z,K=r.disabled,tt=void 0!==K&&K,et=r.tickCount,nt=void 0===et?11:et,rt=r.unit,it=void 0===rt?"Units":rt,ot=r.uomOffset,at=void 0===ot?-15:ot,ut=r.labelOffset,lt=void 0===ut?-7:ut,st=r.onMetrics,ct=r.valueText,ft=void 0===ct?function(t){var e=t.value;t.valueMin;var n=t.valueMax;return void 0===e?"-- / ".concat(n):"".concat(e," / ").concat(n)}:ct,ht=r.onStyleChange,dt=r.displayText;I("LatestDataGauge",{client:k,nodeId:C,variable:N},["client","nodeId","variable"]);var pt=i(null),gt=pt[0],yt=pt[1],vt=i(null),mt=vt[0],xt=vt[1],wt=i(!1),bt=wt[0],_t=wt[1],Mt=i(null),St=Mt[0],At=Mt[1],Tt={value:gt,loading:bt,error:St},kt=i({}),Ct=kt[0],Nt=kt[1],Dt="function"==typeof Q?Q(Tt):Q||{},Ft={container:h(h({},Dt.container),null==Ct?void 0:Ct.container),label:h(h({},Dt.label),null==Ct?void 0:Ct.label),value:h(h({},Dt.value),null==Ct?void 0:Ct.value),unit:h(h({},Dt.unit),null==Ct?void 0:Ct.unit),fontFamily:null!==(u=null==Ct?void 0:Ct.fontFamily)&&void 0!==u?u:Dt.fontFamily,subtitle:h(h(h({},Au),Dt.subtitle),Ct.subtitle),arc:h(h(h({},Su),Dt.arc),Ct.arc)},$t=o(!1),Et=o(0),Ut=o(!1),zt=o(null),jt=_u(Ft.container),It=_u(Ft.label),Ot=_u(Ft.value),Rt=_u(Ft.subtitle),Yt=_u(Ft.unit),Lt=_u(Ft.arc),Pt=ku,Vt=null!==(l=jt.width)&&void 0!==l?l:Pt.width,Ht=null!==(c=jt.height)&&void 0!==c?c:Pt.height,Xt=function(t){return t*Math.PI/180},qt=s(function(){var t,e=Vt/2,n=Ht/2,r=Math.min(Vt/2,Ht/2)-8,i=r,o=Math.max(6,i-(null!=L?L:Math.round(.2*i))),a=Xt(O),u=Xt(Y),l=void 0===gt?void 0:void 0===(t=gt)?void 0:Math.max(E,Math.min(z,t)),s=a+(void 0===l?0:(l-E)/(z-E))*(u-a);return{maxRadius:r,valueAngleDeg:180*s/Math.PI,valueAngleRad:s,startAngleDeg:O,endAngleDeg:Y,innerRadius:o,outerRadius:i,cx:e,cy:n}},[gt,E,z,O,Y,Vt,Ht,L]);a(function(){if(k&&C){var t=k._anedya.NewNode(k,C);xt(t)}},[k,C]),a(function(){if(Ut.current=!0,mt){return p(void 0,void 0,void 0,function(){var t,e,n,r;return g(this,function(i){switch(i.label){case 0:if($t.current||Et.current>=3)return console.log("!node:",mt),console.log("isFetchingRef.current:",$t.current),console.log("failureCountRef.current:",Et.current),[2];$t.current=!0,i.label=1;case 1:return i.trys.push([1,3,4,5]),_t(!0),At(null),[4,mt.getLatestData(N)];case 2:return t=i.sent(),Ut.current?(t.isSuccess&&t.isDataAvailable?(yt(null===(n=t.data)||void 0===n?void 0:n.value),At("")):(yt(null),console.error("error fetching data:",t.error),At(t.error.errorMessage)),Et.current=0,[3,5]):[2];case 3:return e=i.sent(),Ut.current?(console.error("Error fetching latest data:",e),yt(null),At(null!==(r=null==e?void 0:e.message)&&void 0!==r?r:"Failed to fetch data"),Et.current+=1,[3,5]):[2];case 4:return Ut.current?(_t(!1),$t.current=!1,[7]):[2];case 5:return[2]}})}),function(){Ut.current=!1}}},[mt,N]),a(function(){if("function"==typeof ht){var t=ht(gt);t&&"object"==typeof t&&Nt(t)}},[gt]);var Bt=dt?dt(Number(gt),it):{text:String(null!=gt?gt:""),unitText:it,position:"right",unitStyle:"normal"};a(function(){st&&st(qt)},[qt,st]),a(function(){var t,e,n,r,i,o,a,u,l=zt.current;if(l){Te(l).selectAll("*").remove();var s=Te(l),c=qt.cx,f=qt.cy,h=qt.outerRadius,d=qt.innerRadius,p=qt.valueAngleRad,g=qt.startAngleDeg,y=qt.endAngleDeg,v=s.append("g").attr("transform","translate(".concat(c,", ").concat(f,")")),m=Xt(g),x=Xt(y),w=Ia().innerRadius(d).outerRadius(h).startAngle(m).endAngle(x)(void 0);v.append("path").attr("d",null!=w?w:"").attr("fill",null!==(t=Lt.trackColor)&&void 0!==t?t:"#e6e6e6").attr("stroke","none");var b=Xt(y-g),_=function(t){return m+(t-E)/(z-E)*b},M=(null!=V?V:[]).map(function(t){return{from:Math.max(t.from,E),to:Math.min(t.to,z),color:t.color}}).filter(function(t){return t.to>t.from}).sort(function(t,e){return t.from-e.from});if(M.forEach(function(t,e){var n=_(t.from),r=_(t.to),i=Ia().innerRadius(d).outerRadius(h).startAngle(n).endAngle(r)(void 0);v.append("path").attr("d",null!=i?i:"").attr("fill",t.color).attr("stroke","none").attr("opacity",1)}),void 0!==gt){var S=Ia().innerRadius(d).outerRadius(h).startAngle(m).endAngle(p)(void 0);v.append("path").attr("d",null!=S?S:"").attr("fill",null!==(e=Lt.progressColor)&&void 0!==e?e:"rgba(255,255,255,0.15)").attr("stroke",null!==(n=Lt.progressStroke)&&void 0!==n?n:"#00000000")}if(X&&void 0!==gt){var A=(d+h)/2+.15*(h-d),T=v.append("g").attr("class","needle");Va();var k=Math.cos(p-Math.PI/2)*A,C=Math.sin(p-Math.PI/2)*A;T.append("line").attr("x1",0).attr("y1",0).attr("x2",k).attr("y2",C).attr("stroke",B).attr("stroke-width",J).attr("stroke-linecap","round"),T.append("circle").attr("cx",0).attr("cy",0).attr("r",Math.max(3,Math.min(6,.25*(h-d)))).attr("fill",B)}var N=ft({value:gt,valueMin:E,valueMax:z}),D=v.append("g").attr("class","value-group");return D.append("text").attr("class","gauge-value-text").attr("text-anchor","middle").attr("y",-(d+h)/2*.05).style("font-size",null!==(r=Lt.fontSize)&&void 0!==r?r:"".concat(Math.round(.45*d),"px")).style("font-family",null!==(i=Lt.fontFamily)&&void 0!==i?i:"Roboto, Arial, sans-serif").style("fill",null!==(o=Ot.color)&&void 0!==o?o:"#111").text(N),G&&D.append("text").attr("class","gauge-subtitle-text").attr("text-anchor","middle").attr("y",.6*(h-d)+14).style("font-size",null!==(a=Rt.fontSize)&&void 0!==a?a:"12px").style("fill",null!==(u=Rt.color)&&void 0!==u?u:"#666").text(G),function(){Te(l).selectAll("*").remove()}}},[qt,V,gt,E,z,X,B,J,ft,Ft]);var Wt=function(t,e,n){return{color:"url(#".concat(n,")")}}(0,0,"redFade-randomkey"),Jt=[{min:0,max:.5,color:"rgb(181,230,29)"},{min:.5,max:1,color:"orange"},h({min:.75,max:1},Wt)],Gt=.15*Math.min(Number(Vt),Number(Ht)),Zt=null!==(d=null===(f=null==Ft?void 0:Ft.label)||void 0===f?void 0:f.fontSize)&&void 0!==d?d:.6*Gt,Qt=null!==(v=null===(y=null==Ft?void 0:Ft.value)||void 0===y?void 0:y.fontSize)&&void 0!==v?v:1.2*Gt,Kt=null!==(x=null===(m=null==Ft?void 0:Ft.unit)||void 0===m?void 0:m.fontSize)&&void 0!==x?x:.8*Gt,te=h(h(h({},ku),jt),{width:Vt,height:Ht}),ee=null!==(w=null==Ft?void 0:Ft.fontFamily)&&void 0!==w?w:"Roboto",ne=null!==(_=null===(b=ku.label)||void 0===b?void 0:b.fontFamily)&&void 0!==_?_:ee,re=null!==(S=null===(M=ku.value)||void 0===M?void 0:M.fontFamily)&&void 0!==S?S:ee,ie=null!==(T=null===(A=ku.label)||void 0===A?void 0:A.fontFamily)&&void 0!==T?T:ee,oe=h(h(h(h({},ku.label),{fontSize:Zt}),It),{fontFamily:ne}),ae=h(h(h(h({},ku.value),{fontSize:Qt}),Ot),{fontFamily:re}),ue=h(h(h(h({},ku.unit),{fontSize:Kt}),Yt),{fontFamily:ie});return t("div",{style:h({},te),children:[F&&e("h2",{style:h({},oe),children:F}),bt?e("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",height:"100%"},children:e("div",{className:"spinner",style:{width:.3*Math.min(Number(Vt),Number(Ht)),height:.3*Math.min(Number(Vt),Number(Ht))}})}):St?e("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:e("div",{style:{background:"rgba(255, 0, 0, 0.15)",border:"1px solid rgba(255, 0, 0, 0.6)",boxShadow:"rgba(149, 157, 165, 0.2) 0px 8px 24px",color:"rgba(255, 0, 0, 0.6)",textAlign:"center",borderRadius:"5px",padding:"5px"},children:St})}):gt?e(bu,{height:400,width:400,min:0,max:100,value:gt,maxAngle:Y,minAngle:O,disabled:tt,pointerLabel:tt?"Disabled":gt+"",tickCount:Number(nt),uom:it,uomProps:{offsetText:at},labelProps:{offsetText:lt},arcSegments:Jt,mergedValueSx:ae,mergedUnitSx:ue,formatted:Bt}):gt?e(n,{}):e("div",{style:{fontSize:"25px",display:"flex",justifyContent:"center",alignItems:"center",height:"100%",paddingRight:"10px",paddingLeft:"10px"},children:e("div",{style:{color:"#757575",textAlign:"center",borderRadius:"5px",padding:"5px"},children:"No data available"})})]})};export{fu as ChartWidget,Cu as LatestDataGauge,V as LatestDataWidget,j as anedyaClientInit}; -//# sourceMappingURL=index.mjs.map +// src/components/CardWidget.tsx +import { useEffect, useMemo, useRef, useState } from "react"; +import { twMerge } from "tailwind-merge"; + +// src/themes/defaultTheme.ts +var CARD_DEFAULT_CLASSES = { + title: "text-[length:var(--anedya-card-title-size)] font-medium", + value: "text-[length:var(--anedya-card-value-size)] font-bold", + unit: "text-[length:var(--anedya-card-unit-size)]", + label: "text-[length:var(--anedya-card-label-size)]", + container: "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" +}; +var lightTheme = { + classNames: { + container: "bg-white border-slate-200", + title: "text-slate-500", + value: "text-slate-900", + label: "text-slate-400" + } +}; +var darkTheme = { + classNames: { + container: "bg-slate-900 border-slate-800", + title: "text-slate-400", + value: "text-white", + label: "text-slate-500" + } +}; + +// src/components/CardWidget.tsx +import { Fragment, jsx, jsxs } from "react/jsx-runtime"; +var DEFAULT_WIDTH = 240; +var DEFAULT_MIN_WIDTH = 180; +var DEFAULT_MAX_WIDTH = 480; +function CardWidget({ + node, + variable, + title = "Latest Value", + unit, + precision, + formatValue, + labelText, + classNames = {}, + onDataChange, + theme, + className, + width, + height, + minWidth = DEFAULT_MIN_WIDTH, + maxWidth = DEFAULT_MAX_WIDTH +}) { + const [value, setValue] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [dynamicProps, setDynamicProps] = useState({}); + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + useEffect(() => { + if (!node) return; + mountedRef.current = true; + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + try { + const res = await node.getLatestData(variable); + if (!mountedRef.current) return; + if (res.isSuccess && res.isDataAvailable) { + setValue(res.data.value); + setTimestamp(res.data.timestamp); + } else { + setValue(null); + setError(res.error?.errorMessage ?? "No data available"); + } + } catch (err) { + if (!mountedRef.current) return; + setValue(null); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + useEffect(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + const data = value != null && timestamp != null ? { value, timestamp } : null; + setDynamicProps(onDataChange(data) ?? {}); + }, [value, timestamp, onDataChange]); + const resolvedProps = { + title, + unit, + precision, + formatValue, + labelText, + width: width ?? DEFAULT_WIDTH, + height, + minWidth, + maxWidth, + className, + theme, + ...dynamicProps, + classNames: { + ...classNames ?? {}, + ...dynamicProps.classNames ?? {} + } + }; + const resolvedTheme = resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" ? lightTheme : resolvedProps.theme ?? lightTheme; + const resolveSlot = (slot) => twMerge( + CARD_DEFAULT_CLASSES[slot], + resolvedTheme.classNames[slot], + resolvedProps.classNames[slot] + ); + const displayValue = useMemo(() => { + if (value == null) return null; + if (resolvedProps.formatValue) return resolvedProps.formatValue(value); + if (resolvedProps.precision != null) + return value.toFixed(resolvedProps.precision); + return String(value); + }, [value, resolvedProps.formatValue, resolvedProps.precision]); + const displayLabel = useMemo(() => { + if (timestamp == null) return null; + if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); + const d = timestamp < 1e12 ? new Date(timestamp * 1e3) : new Date(timestamp); + return `Updated ${d.toLocaleTimeString()}`; + }, [timestamp, resolvedProps.labelText]); + return /* @__PURE__ */ jsxs( + "div", + { + className: twMerge( + "anedya-card", + resolveSlot("container"), + resolvedProps.className + ), + style: { + width: resolvedProps.width, + minWidth: resolvedProps.minWidth, + maxWidth: resolvedProps.maxWidth, + height: resolvedProps.height, + boxSizing: "border-box" + }, + children: [ + /* @__PURE__ */ jsx("span", { className: resolveSlot("title"), children: resolvedProps.title }), + loading ? /* @__PURE__ */ jsx( + "div", + { + style: { + height: 36, + width: 36, + borderRadius: "50%", + border: "2px solid #cbd5e1", + borderTopColor: "#475569", + animation: "anedya-card-spin 0.8s linear infinite" + }, + children: /* @__PURE__ */ jsx("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) + } + ) : error ? /* @__PURE__ */ jsx("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ jsxs(Fragment, { children: [ + /* @__PURE__ */ jsxs( + "span", + { + className: twMerge( + "inline-flex items-end justify-center gap-1", + resolveSlot("value") + ), + children: [ + /* @__PURE__ */ jsx("span", { children: displayValue }), + resolvedProps.unit && /* @__PURE__ */ jsx("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) + ] + } + ), + displayLabel && /* @__PURE__ */ jsx( + "span", + { + className: resolveSlot("label"), + children: displayLabel + } + ) + ] }) + ] + } + ); +} +export { + CardWidget +}; diff --git a/dist/index.mjs.map b/dist/index.mjs.map deleted file mode 100644 index 56497c2b..00000000 --- a/dist/index.mjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.mjs","sources":["../node_modules/tslib/tslib.es6.js","../node_modules/@anedyasystems/anedya-frontend-sdk/dist/index.mjs","../src/hooks/AnedyaFrontendClient.ts","../src/helpers/validate.ts","../src/components/LatestDataWidget.tsx","../src/hooks/renderLatestData.tsx","../node_modules/d3-array/src/ascending.js","../node_modules/d3-array/src/descending.js","../node_modules/d3-array/src/bisector.js","../node_modules/d3-array/src/bisect.js","../node_modules/d3-array/src/number.js","../node_modules/d3-array/src/ticks.js","../node_modules/d3-axis/src/identity.js","../node_modules/d3-axis/src/axis.js","../node_modules/d3-dispatch/src/dispatch.js","../node_modules/d3-selection/src/namespaces.js","../node_modules/d3-selection/src/namespace.js","../node_modules/d3-selection/src/creator.js","../node_modules/d3-selection/src/selector.js","../node_modules/d3-selection/src/selectorAll.js","../node_modules/d3-selection/src/selection/selectAll.js","../node_modules/d3-selection/src/array.js","../node_modules/d3-selection/src/matcher.js","../node_modules/d3-selection/src/selection/selectChild.js","../node_modules/d3-selection/src/selection/selectChildren.js","../node_modules/d3-selection/src/selection/sparse.js","../node_modules/d3-selection/src/selection/enter.js","../node_modules/d3-selection/src/selection/data.js","../node_modules/d3-selection/src/selection/sort.js","../node_modules/d3-selection/src/selection/attr.js","../node_modules/d3-selection/src/window.js","../node_modules/d3-selection/src/selection/style.js","../node_modules/d3-selection/src/selection/property.js","../node_modules/d3-selection/src/selection/classed.js","../node_modules/d3-selection/src/selection/text.js","../node_modules/d3-selection/src/selection/html.js","../node_modules/d3-selection/src/selection/raise.js","../node_modules/d3-selection/src/selection/lower.js","../node_modules/d3-selection/src/selection/insert.js","../node_modules/d3-selection/src/selection/remove.js","../node_modules/d3-selection/src/selection/clone.js","../node_modules/d3-selection/src/selection/on.js","../node_modules/d3-selection/src/selection/dispatch.js","../node_modules/d3-selection/src/selection/index.js","../node_modules/d3-selection/src/select.js","../node_modules/d3-color/src/define.js","../node_modules/d3-color/src/color.js","../node_modules/d3-selection/src/selection/select.js","../node_modules/d3-selection/src/selection/filter.js","../node_modules/d3-selection/src/constant.js","../node_modules/d3-selection/src/selection/exit.js","../node_modules/d3-selection/src/selection/join.js","../node_modules/d3-selection/src/selection/merge.js","../node_modules/d3-selection/src/selection/order.js","../node_modules/d3-selection/src/selection/call.js","../node_modules/d3-selection/src/selection/nodes.js","../node_modules/d3-selection/src/selection/node.js","../node_modules/d3-selection/src/selection/size.js","../node_modules/d3-selection/src/selection/empty.js","../node_modules/d3-selection/src/selection/each.js","../node_modules/d3-selection/src/selection/append.js","../node_modules/d3-selection/src/selection/datum.js","../node_modules/d3-selection/src/selection/iterator.js","../node_modules/d3-interpolate/src/constant.js","../node_modules/d3-interpolate/src/color.js","../node_modules/d3-interpolate/src/rgb.js","../node_modules/d3-interpolate/src/numberArray.js","../node_modules/d3-interpolate/src/array.js","../node_modules/d3-interpolate/src/date.js","../node_modules/d3-interpolate/src/number.js","../node_modules/d3-interpolate/src/object.js","../node_modules/d3-interpolate/src/string.js","../node_modules/d3-interpolate/src/value.js","../node_modules/d3-interpolate/src/round.js","../node_modules/d3-interpolate/src/transform/decompose.js","../node_modules/d3-interpolate/src/transform/parse.js","../node_modules/d3-interpolate/src/transform/index.js","../node_modules/d3-timer/src/timer.js","../node_modules/d3-timer/src/timeout.js","../node_modules/d3-transition/src/transition/schedule.js","../node_modules/d3-transition/src/transition/tween.js","../node_modules/d3-transition/src/transition/interpolate.js","../node_modules/d3-transition/src/transition/attr.js","../node_modules/d3-transition/src/transition/attrTween.js","../node_modules/d3-transition/src/transition/delay.js","../node_modules/d3-transition/src/transition/duration.js","../node_modules/d3-transition/src/transition/selection.js","../node_modules/d3-transition/src/transition/style.js","../node_modules/d3-transition/src/transition/index.js","../node_modules/d3-transition/src/transition/select.js","../node_modules/d3-transition/src/transition/selectAll.js","../node_modules/d3-transition/src/transition/filter.js","../node_modules/d3-transition/src/transition/merge.js","../node_modules/d3-transition/src/transition/transition.js","../node_modules/d3-transition/src/transition/on.js","../node_modules/d3-transition/src/transition/styleTween.js","../node_modules/d3-transition/src/transition/text.js","../node_modules/d3-transition/src/transition/textTween.js","../node_modules/d3-transition/src/transition/remove.js","../node_modules/d3-transition/src/transition/ease.js","../node_modules/d3-transition/src/transition/easeVarying.js","../node_modules/d3-transition/src/transition/end.js","../node_modules/d3-transition/src/selection/transition.js","../node_modules/d3-ease/src/cubic.js","../node_modules/d3-transition/src/selection/index.js","../node_modules/d3-transition/src/selection/interrupt.js","../node_modules/d3-transition/src/interrupt.js","../node_modules/d3-path/src/path.js","../node_modules/d3-format/src/formatDecimal.js","../node_modules/d3-format/src/exponent.js","../node_modules/d3-format/src/formatSpecifier.js","../node_modules/d3-format/src/formatPrefixAuto.js","../node_modules/d3-format/src/formatRounded.js","../node_modules/d3-format/src/formatTypes.js","../node_modules/d3-format/src/identity.js","../node_modules/d3-format/src/locale.js","../node_modules/d3-format/src/defaultLocale.js","../node_modules/d3-format/src/formatGroup.js","../node_modules/d3-format/src/formatNumerals.js","../node_modules/d3-format/src/formatTrim.js","../node_modules/d3-scale/src/init.js","../node_modules/d3-scale/src/number.js","../node_modules/d3-scale/src/continuous.js","../node_modules/d3-scale/src/constant.js","../node_modules/d3-scale/src/tickFormat.js","../node_modules/d3-format/src/precisionPrefix.js","../node_modules/d3-format/src/precisionRound.js","../node_modules/d3-format/src/precisionFixed.js","../node_modules/d3-scale/src/linear.js","../node_modules/d3-time/src/interval.js","../node_modules/d3-time/src/millisecond.js","../node_modules/d3-time/src/duration.js","../node_modules/d3-time/src/second.js","../node_modules/d3-time/src/minute.js","../node_modules/d3-time/src/hour.js","../node_modules/d3-time/src/day.js","../node_modules/d3-time/src/week.js","../node_modules/d3-time/src/month.js","../node_modules/d3-time/src/year.js","../node_modules/d3-time/src/ticks.js","../node_modules/d3-time-format/src/locale.js","../node_modules/d3-time-format/src/defaultLocale.js","../node_modules/d3-scale/src/time.js","../node_modules/d3-scale/src/nice.js","../node_modules/d3-shape/src/constant.js","../node_modules/d3-shape/src/math.js","../node_modules/d3-shape/src/path.js","../node_modules/d3-shape/src/arc.js","../node_modules/d3-shape/src/array.js","../node_modules/d3-shape/src/curve/linear.js","../node_modules/d3-shape/src/point.js","../node_modules/d3-shape/src/line.js","../node_modules/d3-shape/src/area.js","../node_modules/d3-shape/src/curve/radial.js","../node_modules/d3-shape/src/lineRadial.js","../node_modules/d3-shape/src/symbol/circle.js","../node_modules/d3-shape/src/symbol/triangle.js","../node_modules/d3-shape/src/symbol.js","../node_modules/d3-shape/src/curve/monotone.js","../node_modules/d3-zoom/src/transform.js","../src/helpers/formatDate.ts","../node_modules/style-inject/dist/style-inject.es.js","../src/components/ChartWidget.tsx","../node_modules/d3-array/src/extent.js","../node_modules/d3-array/src/max.js","../src/components/Gauge/components/SVGBase/SVGBase.tsx","../src/components/Gauge/components/Pointer/Pointer.tsx","../src/components/Gauge/components/InvertedTriangle/InvertedTriangle.tsx","../src/components/Gauge/components/UnitOfMeasurement/UnitOfMeasurement.tsx","../src/components/Gauge/components/GaugeArc/GaugeArc.tsx","../src/components/Gauge/components/Label/Label.tsx","../src/components/Gauge/components/Gradient/Gradient.tsx","../src/components/Gauge/Gauge.tsx","../src/components/LatestDataGauge.tsx","../src/components/Gauge/hooks/useGradient.tsx"],"sourcesContent":["/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\r\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\r\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\r\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\r\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\r\n var _, done = false;\r\n for (var i = decorators.length - 1; i >= 0; i--) {\r\n var context = {};\r\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\r\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\r\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\r\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\r\n if (kind === \"accessor\") {\r\n if (result === void 0) continue;\r\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\r\n if (_ = accept(result.get)) descriptor.get = _;\r\n if (_ = accept(result.set)) descriptor.set = _;\r\n if (_ = accept(result.init)) initializers.unshift(_);\r\n }\r\n else if (_ = accept(result)) {\r\n if (kind === \"field\") initializers.unshift(_);\r\n else descriptor[key] = _;\r\n }\r\n }\r\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\r\n done = true;\r\n};\r\n\r\nexport function __runInitializers(thisArg, initializers, value) {\r\n var useValue = arguments.length > 2;\r\n for (var i = 0; i < initializers.length; i++) {\r\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\r\n }\r\n return useValue ? value : void 0;\r\n};\r\n\r\nexport function __propKey(x) {\r\n return typeof x === \"symbol\" ? x : \"\".concat(x);\r\n};\r\n\r\nexport function __setFunctionName(f, name, prefix) {\r\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\r\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\r\n};\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\r\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\r\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nvar ownKeys = function(o) {\r\n ownKeys = Object.getOwnPropertyNames || function (o) {\r\n var ar = [];\r\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\r\n return ar;\r\n };\r\n return ownKeys(o);\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n\r\nexport function __addDisposableResource(env, value, async) {\r\n if (value !== null && value !== void 0) {\r\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\r\n var dispose, inner;\r\n if (async) {\r\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\r\n dispose = value[Symbol.asyncDispose];\r\n }\r\n if (dispose === void 0) {\r\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\r\n dispose = value[Symbol.dispose];\r\n if (async) inner = dispose;\r\n }\r\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\r\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\r\n env.stack.push({ value: value, dispose: dispose, async: async });\r\n }\r\n else if (async) {\r\n env.stack.push({ async: true });\r\n }\r\n return value;\r\n\r\n}\r\n\r\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\r\n var e = new Error(message);\r\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\r\n};\r\n\r\nexport function __disposeResources(env) {\r\n function fail(e) {\r\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\r\n env.hasError = true;\r\n }\r\n var r, s = 0;\r\n function next() {\r\n while (r = env.stack.pop()) {\r\n try {\r\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\r\n if (r.dispose) {\r\n var result = r.dispose.call(r.value);\r\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\r\n }\r\n else s |= 1;\r\n }\r\n catch (e) {\r\n fail(e);\r\n }\r\n }\r\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\r\n if (env.hasError) throw env.error;\r\n }\r\n return next();\r\n}\r\n\r\nexport function __rewriteRelativeImportExtension(path, preserveJsx) {\r\n if (typeof path === \"string\" && /^\\.\\.?\\//.test(path)) {\r\n return path.replace(/\\.(tsx)$|((?:\\.d)?)((?:\\.[^./]+?)?)\\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {\r\n return tsx ? preserveJsx ? \".jsx\" : \".js\" : d && (!ext || !cm) ? m : (d + ext + \".\" + cm.toLowerCase() + \"js\");\r\n });\r\n }\r\n return path;\r\n}\r\n\r\nexport default {\r\n __extends: __extends,\r\n __assign: __assign,\r\n __rest: __rest,\r\n __decorate: __decorate,\r\n __param: __param,\r\n __esDecorate: __esDecorate,\r\n __runInitializers: __runInitializers,\r\n __propKey: __propKey,\r\n __setFunctionName: __setFunctionName,\r\n __metadata: __metadata,\r\n __awaiter: __awaiter,\r\n __generator: __generator,\r\n __createBinding: __createBinding,\r\n __exportStar: __exportStar,\r\n __values: __values,\r\n __read: __read,\r\n __spread: __spread,\r\n __spreadArrays: __spreadArrays,\r\n __spreadArray: __spreadArray,\r\n __await: __await,\r\n __asyncGenerator: __asyncGenerator,\r\n __asyncDelegator: __asyncDelegator,\r\n __asyncValues: __asyncValues,\r\n __makeTemplateObject: __makeTemplateObject,\r\n __importStar: __importStar,\r\n __importDefault: __importDefault,\r\n __classPrivateFieldGet: __classPrivateFieldGet,\r\n __classPrivateFieldSet: __classPrivateFieldSet,\r\n __classPrivateFieldIn: __classPrivateFieldIn,\r\n __addDisposableResource: __addDisposableResource,\r\n __disposeResources: __disposeResources,\r\n __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,\r\n};\r\n","var R=class{tokenId;token;baseUrl;constructor(e,s){if(!e||e.trim()===\"\")throw new Error(\"Token ID is required\");if(!s||s.trim()===\"\")throw new Error(\"Token is required\");this.tokenId=e,this.token=s,this.baseUrl=\"https://api.anedya.io/v1\";}};var D=class{tokenId;tokenBytes;signatureVersionBytes;signatureVersion=\"v1\";authorizationMode=\"ANEDYASIGV1\";baseUrl;constructor(e){let{token:s,tokenId:a}=e;this.tokenId=a,this.signatureVersionBytes=new TextEncoder().encode(this.signatureVersion),this.tokenBytes=new TextEncoder().encode(s),this.baseUrl=e.baseUrl;}};var T=class{constructor(e,s,a,u=1e4,c=\"desc\"){this.variable=e;this.from=s;this.to=a;this.limit=u;this.order=c;if(c!==\"asc\"&&c!==\"desc\")throw new Error(\"Invalid order value. It should be either 'asc' or 'desc'.\");if(u<1)throw new Error(\"Invalid limit value. It should be at least 1.\");if(s>a)throw new Error(\"Invalid time range. 'from' should be less than or equal to 'to'.\")}},p=class{isSuccess;error;isDataAvailable;data;count;startTime;endTime;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.isDataAvailable=false,this.data=null,this.count=0,this.startTime=0,this.endTime=0;}},g=class{isSuccess;error;isDataAvailable;data;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.isDataAvailable=false,this.data=null;}},N=class{constructor(e,s,a,u){this.namespace=e;this.key=s;this.value=a;this.type=u;if(this.namespace.scope!==\"global\"&&this.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\");if(this.type!==\"string\"&&this.type!==\"binary\"&&this.type!==\"float\"&&this.type!==\"boolean\")throw new Error(\"Invalid type value. It should be either 'string', 'binary', 'float', or 'boolean'.\")}},h=class{isSuccess;error;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"};}},C=class{constructor(e,s){this.namespace=e;this.key=s;if(this.namespace.scope!==\"global\"&&this.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\")}},b=class{isSuccess;error;namespace;key;value;type;size;modified;created;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.namespace={scope:\"\",id:\"\"},this.key=\"\",this.value=void 0,this.type=\"\",this.size=0,this.modified=0,this.created=0;}},K=class{constructor(e,s){this.namespace=e;this.key=s;if(this.namespace.scope!==\"global\"&&this.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\")}},A=class{isSuccess;error;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"};}},x=class{constructor(e,s,a,u,c){this.filter=e;this.orderby=s;this.order=a;this.limit=u;this.offset=c;if(this.filter.namespace.scope!==\"global\"&&this.filter.namespace.scope!==\"node\")throw new Error(\"Invalid namespace scope. It should be either 'global' or 'node'.\")}},I=class{isSuccess;error;count;totalCount;data;next;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.count=0,this.totalCount=0,this.data=void 0,this.next=0;}},S=class{isSuccess;error;data;constructor(){this.isSuccess=false,this.error={errorMessage:\"\",reasonCode:\"\"},this.data=void 0;}},v=class{constructor(e,s){this.time=e;this.variable=s;if(!Number.isFinite(e)||e<=0)throw new Error(\"Invalid time: must be a positive number (UNIX timestamp).\");let a=Math.floor(Date.now()/1e3);if(e>a)throw new Error(\"Invalid time: timestamp cannot be in the future.\");if(!s||typeof s!=\"string\")throw new Error(\"Invalid variable: must be a non-empty string.\")}},f=class{isSuccess;error;count;data;constructor(){this.error={errorMessage:\"\",reasonCode:\"\"},this.isSuccess=false,this.count=0,this.data=[];}};var m=async(o,e,s)=>{try{let u=new TextEncoder().encode(JSON.stringify(o)),c=await crypto.subtle.digest(\"SHA-256\",u),l=new Uint8Array(c),y=new Uint8Array(8);new DataView(y.buffer).setBigUint64(0,BigInt(s),!1);let d=new Uint8Array(l.length+y.length+e.signatureVersionBytes.length+e.tokenBytes.length);d.set(l,0),d.set(y,l.length),d.set(e.signatureVersionBytes,l.length+y.length),d.set(e.tokenBytes,l.length+y.length+e.signatureVersionBytes.length);let i=await crypto.subtle.digest(\"SHA-256\",d);return Array.from(new Uint8Array(i)).map(t=>t.toString(16).padStart(2,\"0\")).join(\"\")}catch(a){console.log(a);}};var G=async(o,e,s,a)=>{let u=`${o}/data/getData`,c={nodes:s,variable:a.variable,from:Math.floor(a.from/1e3),to:Math.floor(a.to/1e3),limit:a.limit,order:a.order},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new p;try{let t=await i.json();if(r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isDataAvailable=!1,r.data=null,t.success){let n=t.data;n==null||n==null||Object.keys(n).length===0?r.isDataAvailable=!1:s.length===1?(n=n[s.toString()],r.data=n,r.isDataAvailable=!0):(r.data=n,r.isDataAvailable=!0);}return r.count=t.count,r.startTime=t.startTime,r.endTime=t.endTime,r}catch{return r.isSuccess=!1,r.error.reasonCode=i.status.toString(),r.error.errorMessage=i.statusText,r}}catch(d){throw console.error(\"Error during Get data request:\",d),d}},k=async(o,e,s,a)=>{let u=`${o}/data/latest`,c={nodes:s,variable:a.variable},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new g;try{let t=await i.json();if(r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isDataAvailable=!1,r.data=null,t.success){let n=t.data;n==null||n==null||Object.keys(n).length===0?r.isDataAvailable=!1:s.length===1?(n=n[s.toString()],r.data=n,r.isDataAvailable=!0):(r.data=n,r.isDataAvailable=!0);}return r}catch{return r.isSuccess=!1,r.error.reasonCode=i.status.toString(),r.error.errorMessage=i.statusText,r}}catch(d){throw console.error(\"Error during get latest data request:\",d),d}};var V=async(o,e,s,a)=>{let u=`${o}/valuestore/setValue`,c;a.namespace.scope===\"node\"?c=s[0]:c=a.namespace.id;let l={namespace:{scope:a.namespace.scope,id:c},key:a.key,value:a.value,type:a.type},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new h;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during set key: \",i),i}},O=async(o,e,s,a)=>{let u=`${o}/valuestore/getValue`,c;a.namespace.scope===\"node\"?c=s[0]:c=a.namespace.id;let l={namespace:{scope:a.namespace.scope,id:c},key:a.key},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new b;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t.namespace=n.namespace,t.key=n.key,t.value=n.value,t.type=n.type,t.size=n.size,t.modified=n.modified,t.created=n.created,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during get key request: \",i),i}},q=async(o,e,s,a)=>{let u=`${o}/valuestore/delete`,c;a.namespace.scope===\"node\"?c=s[0]:c=a.namespace.id;let l={namespace:{scope:a.namespace.scope,id:c},key:a.key},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new A;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during fetch operation:\",i),i}},M=async(o,e,s,a)=>{let u=`${o}/valuestore/scan`,c;a.filter.namespace.scope===\"node\"?c=s[0]:c=a.filter.namespace.id;let l={filter:{namespace:{scope:a.filter.namespace.scope,id:c}},orderby:a.orderby,order:a.order,limit:a.limit,offset:a.offset},y=Math.floor(Date.now()/1e3),d=await m(l,e,y);try{let i={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":y.toString(),\"X-Anedya-Signature\":d,\"Content-Type\":\"application/json\"},r=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:i,body:JSON.stringify(l)}),t=new I;try{let n=await r.json();return t.isSuccess=n.success,t.error.errorMessage=n.error,t.error.reasonCode=n.reasonCode,t.count=n.count,t.totalCount=n.totalCount,t.data=n.data,t.next=n.next,t}catch{return t.isSuccess=!1,t.error.errorMessage=r.statusText,t.error.reasonCode=r.status.toString(),t}}catch(i){throw console.error(\"Error during scan vs operation: \",i),i}};var U=async(o,e,s,a)=>{let u=`${o}/health/status`,c={nodes:s,lastContactThreshold:a},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new S;try{let t=await i.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isSuccess&&(s.length===1?r.data=t.data[s[0]]:r.data=t.data),r}catch{return r.isSuccess=!1,r.error.errorMessage=i.statusText,r.error.reasonCode=i.status.toString(),r}}catch(d){throw console.error(\"Error during fetch operation:\",d),d}};var P=async(o,e,s,a)=>{let u=`${o}/data/snapshot`,c={nodes:s,time:a?.time,variable:a?.variable},l=Math.floor(Date.now()/1e3),y=await m(c,e,l);try{let d={Authorization:e.authorizationMode,\"x-Anedya-SignatureVersion\":e.signatureVersion,\"X-Anedya-Tokenid\":e.tokenId,\"X-Anedya-Timestamp\":l.toString(),\"X-Anedya-Signature\":y,\"Content-Type\":\"application/json\"},i=await fetch(u,{method:\"POST\",credentials:\"same-origin\",headers:d,body:JSON.stringify(c)}),r=new f;try{let t=await i.json();return r.isSuccess=t.success,r.error.errorMessage=t.error,r.error.reasonCode=t.reasonCode,r.isSuccess&&(s.length===1?r.data=t.data.filter(n=>n.node===s[0]):r.data=t.data,r.count=t.count),r}catch{return r.isSuccess=!1,r.error.errorMessage=i.statusText,r.error.reasonCode=i.status.toString(),r}}catch(d){throw console.error(\"Error during fetch operation:\",d),d}};var w=class{#e;#t;#r;constructor(e,s){let{baseUrl:a,tokenId:u,tokenBytes:c,signatureVersionBytes:l,signatureVersion:y,authorizationMode:d}=e;this.#e=s,this.#t=a,this.#r={tokenId:u,tokenBytes:c,signatureVersion:y,signatureVersionBytes:l,authorizationMode:d};}getNodeId(){return this.#e}async getData(e){return await G(this.#t,this.#r,[this.#e],e)}async getLatestData(e){let s={variable:e};return await k(this.#t,this.#r,[this.#e],s)}async setKey(e){return await V(this.#t,this.#r,[this.#e],e)}async getKey(e){return await O(this.#t,this.#r,[this.#e],e)}async deleteKey(e){return await q(this.#t,this.#r,[this.#e],e)}async scanKeys(e){return await M(this.#t,this.#r,[this.#e],e)}async getDeviceStatus(e){return await U(this.#t,this.#r,[this.#e],e)}async getSnapshot(e){return await P(this.#t,this.#r,[this.#e],e)}};var E=class{NewConfig(e,s){return new R(e,s)}NewClient(e){return new D(e)}NewNode(e,s){return new w(e,s)}};var B=(s=>(s.GLOBAL=\"global\",s.NODE=\"node\",s))(B||{}),X=(u=>(u.STRING=\"string\",u.BINARY=\"binary\",u.FLOAT=\"float\",u.BOOLEAN=\"boolean\",u))(X||{});var _={Success:-1,Unknown:0,Failure:1,HttpRequestError:3,HttpRequestTimeout:4,keyNotFound:5};function z(o){return Object.fromEntries(Object.entries(_).map(([s,a])=>[a,s]))[o]||\"UnknownErrorCode\"}\nexport{E as Anedya,X as AnedyaDataType,K as AnedyaDeleteKeyReq,A as AnedyaDeleteKeyResp,_ as AnedyaError,T as AnedyaGetDataReq,p as AnedyaGetDataResp,S as AnedyaGetDeviceStatusResp,C as AnedyaGetKeyReq,b as AnedyaGetKeyResp,g as AnedyaGetLatestDataResp,v as AnedyaGetSnapshotReq,f as AnedyaGetSnapshotResp,x as AnedyaScanKeysReq,I as AnedyaScanKeysResp,B as AnedyaScope,N as AnedyaSetKeyReq,h as AnedyaSetKeyResp,z as getAnedyaErrorMessage};//# sourceMappingURL=index.mjs.map\n//# sourceMappingURL=index.mjs.map","import { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\nimport { AnedyaClient } from \"../components/types\";\n\nlet globalClient: AnedyaClient | null = null;\n\n// --- Global rate limiter map ---\ntype RateLimiter = {\n lastCallTime: number;\n interval: number;\n};\n\nconst nodeRateLimiters = new Map();\n\n\n// --- Type for InitOptions ---\ninterface InitOptions {\n useGlobal?: boolean;\n forceReinit?: boolean;\n rateLimitMs?: number; // βœ… configurable rate limit interval\n}\n\n/**\n * Initialize the Anedya client and optionally store globally.\n *\n * @returns client\n */\n\nexport function anedyaClientInit(\n tokenId: string,\n token: string,\n options?: InitOptions\n): AnedyaClient {\n const useGlobal = options?.useGlobal ?? false;\n const forceReinit = options?.forceReinit ?? false;\n const rateLimitMs = options?.rateLimitMs ?? 100; // βœ… default: 10 seconds\n\n if (useGlobal && globalClient && !forceReinit) {\n return globalClient;\n }\n\n const anedya = new Anedya();\n const config = anedya.NewConfig(tokenId, token);\n const client = anedya.NewClient(config);\n\n // --- Patch NewNode with per-node rate limiter ---\n const originalNewNode: (...args: any[]) => any = anedya.NewNode.bind(anedya);\n\n anedya.NewNode = (...args: any[]): any => {\n const node = originalNewNode(...args); // βœ… now properly typed\n\n // Extract nodeId (second argument)\n const nodeId = typeof args[1] === \"string\" ? args[1] : `unknown-${Date.now()}`;\n\n const limiter =\n nodeRateLimiters.get(nodeId) || {\n lastCallTime: 0,\n interval: rateLimitMs, // βœ… use configurable rate limit\n };\n nodeRateLimiters.set(nodeId, limiter);\n\n if (node.getLatestData) {\n const originalGetLatestData: (...params: any[]) => Promise =\n node.getLatestData.bind(node);\n\n node.getLatestData = async (...params: any[]): Promise => {\n const now = Date.now();\n const elapsed = now - limiter.lastCallTime;\n\n if (elapsed < limiter.interval) {\n const wait = limiter.interval - elapsed;\n console.warn(\n `⏳ Rate limited for node ${nodeId}: waiting ${wait}ms before next call`\n );\n await new Promise((r) => setTimeout(r, wait));\n }\n\n limiter.lastCallTime = Date.now();\n\n try {\n return await originalGetLatestData(...params);\n } catch (err) {\n console.error(`⚠️ API call failed for node ${nodeId}:`, err);\n throw err;\n }\n };\n }\n\n return node;\n };\n\n // Attach wrapped anedya instance to client\n (client as any)._anedya = anedya;\n\n if (useGlobal) {\n globalClient = client;\n }\n\n return client;\n}\n\n\n/**\n * Retrieve the globally initialized Anedya instance and client.\n */\nexport function getAnedyaClient(): AnedyaClient {\n if (!globalClient) {\n throw new Error(\n \"Anedya client not initialized! Call anedyaClientInit first.\"\n );\n }\n return globalClient;\n}\n\n/**\n * Clear the global Anedya client (for logout/reset).\n */\nexport function resetAnedyaClient(): void {\n globalClient = null;\n}\n","export function validateRequiredProps(\n componentName: string,\n props: Record,\n required: string[]\n) {\n const missing = required.filter((key) => props[key] === undefined);\n\n if (missing.length === 0) return;\n\n const message = `[${componentName}] Missing required prop(s): ${missing.join(\n \", \"\n )}`;\n\n\n\n console.error(message);\n \n}\n","import React, { useEffect, useMemo, useRef, useState } from \"react\";\nimport { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\nimport { CSSProperties } from \"react\";\nimport { validateRequiredProps } from \"../helpers/validate\";\n// --- Default color ranges ---\nconst defaultColorRanges = [\n { max: 40, color: \"#008000\" },\n { max: 100, color: \"#FFA500\" },\n { max: Infinity, color: \"#FF2C2C\" },\n];\n\ntype WidgetState = {\n value?: number;\n loading: boolean;\n error?: string|null;\n};\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\ninterface DisplayTextResult {\n text: string;\n unitText?: string;\n position?: UnitPosition;\n unitStyle?: UnitStyle;\n}\n\ntype DisplayTextFormatter = (\n value: number,\n unit?: string\n) => DisplayTextResult;\n\n// --- Default styles ---\ninterface StyleSet {\n container?: CSSProperties;\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\n fontFamily?: string; // optional global font family for all 3\n}\n\n\ntype StylesInput =\n | StyleSet\n | ((state: WidgetState) => StyleSet);\n\n\n\nconst defaultFontFamily = \"Roboto, sans-serif\";\n\nconst defaultStyles: Required = {\n container: {\n width: 400,\n height: 250,\n padding: 2,\n margin: 0,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",\n borderRadius: 10,\n boxSizing: \"border-box\",\n background: \"rgb(248, 249, 250)\",\n border: \"1px solid rgba(211, 216, 220, 1)\",\n//'linear-gradient(to right, rgb(47, 99, 255), rgb(20, 110, 180))'\n fontFamily: defaultFontFamily,\n color:\"#000000\",\n gap: 2,\n textAlign: \"center\",\n },\n label: { fontWeight: 500, color: \"#000000\", fontFamily: defaultFontFamily },\n value: { fontWeight: 700, color: \"#000000\", fontFamily: defaultFontFamily },\n unit: { fontWeight: 400, color: \"#000000\", fontFamily: defaultFontFamily },\n fontFamily: defaultFontFamily,\n \n};\n\n// --- Helper: get color from range ---\nconst getColorFromRange = (value: number, ranges = defaultColorRanges) => {\n const range = ranges.find((r) => value <= r.max);\n return range?.color ?? \"#333\";\n};\n\n// --- Helper: normalize sx for TypeScript ---\nconst normalizeSx = (\n sx: Record | undefined\n): Record => {\n if (!sx) return {};\n if (Array.isArray(sx)) return Object.assign({}, ...sx);\n if (typeof sx === \"function\") return sx({}) as Record;\n return sx as Record;\n};\n\n// --- Circuit Breaker Config ---\nconst MAX_FAILURES = 3;\n\n// --- Rate limiter settings ---\nconst MIN_FETCH_INTERVAL = 10000; // 10 seconds between fetches\n\n// --- Props ---\ninterface WidgetProps {\n client: any;\n nodeId: string;\n variable: string;\n title?: string;\n unit?: string;\n styles?: StylesInput;\n displayText?: DisplayTextFormatter;\n colorRange?: typeof defaultColorRanges;\n colorRangeCallback?: (value: number, defaultColor: string) => string;\n onStyleChange?:(value:number) =>{}\n}\n\nexport const LatestDataWidgetComponent: React.FC = ({\n client,\n nodeId,\n variable,\n title = \"Latest Data\",\n unit = \"\",\n styles = {},\n displayText,\n colorRange,\n colorRangeCallback,\n onStyleChange\n}) => {\n validateRequiredProps(\"LatestDataWidget\", { client, nodeId, variable }, [\n \"client\",\n \"nodeId\",\n \"variable\",\n ]);\n\n\n const [data, setData] = useState(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(null);\n const [node, setNode] = useState(null); // <-- store node in state\n\n // --- Preventing stale closures / infinite renders ---\n\n const isFetchingRef = useRef(false);\n const failureCountRef = useRef(0);\n const mountedRef = useRef(false);\n const lastFetchRef = useRef(0);\n\n // Build a state object to pass into the callback styles\nconst widgetState = { data, loading, error };\n\n// Resolve function or static style object\nconst [dynamicStyles, setDynamicStyles] = useState>({});\n\nconst baseResolvedStyles =\n typeof styles === \"function\" ? styles(widgetState) : styles || {};\n\nconst resolvedStyles = {\n container: { ...baseResolvedStyles.container, ...dynamicStyles?.container },\n label: { ...baseResolvedStyles.label, ...dynamicStyles?.label },\n value: { ...baseResolvedStyles.value, ...dynamicStyles?.value },\n unit: { ...baseResolvedStyles.unit, ...dynamicStyles?.unit },\n fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily,\n};\nconst formatted: DisplayTextResult = displayText\n ? displayText(Number(data), unit)\n : {\n text: String(data ?? \"\"),\n unitText: unit,\n position: \"right\",\n unitStyle: \"normal\",\n };\n\n\n \n\n useEffect(() => {\n if (client && nodeId) {\n const anedya = (client as any)._anedya as Anedya; // retrieve wrapped instance\n const createdNode = anedya.NewNode(client, nodeId);\n setNode(createdNode);\n }\n }, [client, nodeId]);\n\n // --- Fetch data once safely ---\n useEffect(() => {\n mountedRef.current = true;\n if (!node) return;\n const fetchData = async () => {\n if (isFetchingRef.current || failureCountRef.current >= MAX_FAILURES) {\n //rate limiter ----> in client\n console.log(\"!node:\", node);\n console.log(\"isFetchingRef.current:\", isFetchingRef.current);\n console.log(\"failureCountRef.current:\", failureCountRef.current);\n return;\n } // don't try if node not ready or if an api call is being currently made already\n\n isFetchingRef.current = true;\n try {\n setLoading(true);\n setError(null);\n const res = await node.getLatestData(variable);\n\n if (!mountedRef.current) return; // <-- SAFE, stops state update if unmounted\n\n if (res.isSuccess && res.isDataAvailable) {\n\n setData(res.data?.value);\n setError(\"\");\n } else {\n setData(null);\n console.error(\"error fetching data:\", res.error);\n setError(res.error.errorMessage);\n }\n failureCountRef.current = 0; // reset on success\n } catch (err: any) {\n if (!mountedRef.current) return;\n console.error(\"Error fetching latest data:\", err);\n setData(null);\n setError(err?.message ?? \"Failed to fetch data\");\n failureCountRef.current += 1;\n } finally {\n if (!mountedRef.current) return;\n setLoading(false);\n isFetchingRef.current = false;\n }\n };\n fetchData();\n\n return () => {\n mountedRef.current = false;\n };\n }, [node, variable]);\n\n\n // Whenever value changes, allow user to modify styles dynamically\n useEffect(() => {\n if (typeof onStyleChange === \"function\") {\n const updated = onStyleChange(data);\n if (updated && typeof updated === \"object\") {\n setDynamicStyles(updated);\n }\n }\n }, [data]);\n\n // --- Normalize styles ---\n const containerSx = normalizeSx(resolvedStyles?.container);\n const labelSx = normalizeSx(resolvedStyles?.label);\n const valueSx = normalizeSx(resolvedStyles?.value);\n const unitSx = normalizeSx(resolvedStyles?.unit);\n\n // --- Container dimensions with TypeScript-safe default ---\n const containerDefaults: any = defaultStyles.container!;\n const width = containerSx.width ?? containerDefaults.width;\n const height = containerSx.height ?? containerDefaults.height;\n\n // --- Scaled font sizes ---\n const baseFont = Math.min(Number(width), Number(height)) * 0.15;\n\n // --- Compute font sizes dynamically if not provided by user ---\n const labelFont = (resolvedStyles?.label as any)?.fontSize ?? baseFont * 0.6;\n\n const valueFont = (resolvedStyles?.value as any)?.fontSize ?? baseFont * 3;\n\n const unitFont = (resolvedStyles?.unit as any)?.fontSize ?? baseFont * 0.8;\n\n // --- Font family handling ---\n const globalFontFamily = resolvedStyles?.fontFamily ?? \"Roboto\";\n const labelFontFamily = labelSx.fontFamily ?? globalFontFamily;\n const valueFontFamily = valueSx.fontFamily ?? globalFontFamily;\n const unitFontFamily = unitSx.fontFamily ?? globalFontFamily;\n\n // --- Gap scaling ---\n const containerGap = (containerSx as any).gap ?? baseFont * 0.2; // scale gap if user didn't pass one\n\n // --- Compute dynamic text color ---\n const finalRange = colorRange ?? defaultColorRanges;\n let textColor = getColorFromRange(Number(data) ?? 0, finalRange);\n if (colorRangeCallback) {\n textColor = colorRangeCallback(Number(data) ?? 0, textColor);\n }\n\n // --- Merge styles safely ---\n const mergedContainerSx: CSSProperties = {\n ...defaultStyles.container,\n ...containerSx,\n \n gap: containerGap,\n\n };\n const mergedLabelSx: CSSProperties = {\n ...defaultStyles.label,\n fontSize: labelFont,\n ...labelSx,\n fontFamily: labelFontFamily,\n };\n const mergedValueSx: CSSProperties = {\n ...defaultStyles.value,\n fontSize: valueFont,\n color: textColor,\n ...valueSx,\n fontFamily: valueFontFamily,\n };\n const mergedUnitSx: CSSProperties = {\n ...defaultStyles.unit,\n fontSize: unitFont,\n ...unitSx,\n fontFamily: unitFontFamily,\n };\n\n\n const renderUnitText = (text: string, style: UnitStyle) => {\n switch (style) {\n case \"superscript\":\n return {text};\n case \"subscript\":\n return {text};\n default:\n return {text};\n }\n};\n\n\n return (\n\n \n {title &&

{title}

}\n\n\n {loading ? (\n \n \n \n ) : error ? (\n
\n \n{error}\n
\n\n \n ) : !data ? (\n
\n \n{ \"No data available\"}\n
\n\n \n ) : (\n <>\n
\n \n {/* Unit LEFT */}\n {formatted.unitText &&\n formatted.position === \"left\" &&\n
\n\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n\n {/* VALUE */}\n
{formatted.text}
\n\n {/* Unit RIGHT */}\n {formatted.unitText &&\n formatted.position === \"right\" &&\n
\n \n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n\n {/* Unit TOP */}\n {formatted.unitText &&\n formatted.position === \"top\" &&\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n\n {/* Unit BOTTOM */}\n {formatted.unitText &&\n formatted.position === \"bottom\" &&\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n }\n
\n \n )}\n \n \n\n\n );\n};\n\nexport default LatestDataWidgetComponent;\n","import React, { useState, useCallback, JSX } from \"react\";\nimport { LatestDataWidgetComponent } from \"../components/LatestDataWidget\";\nimport { AnedyaClient } from \"../components/types\";\nimport { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\n\n// --- Default color ranges ---\nconst defaultColorRanges = [\n { max: 20, color: \"red\" },\n { max: 50, color: \"yellow\" },\n { max: Infinity, color: \"green\" },\n];\nimport { CSSProperties } from \"react\";\n\n// --- Default styles ---\ninterface StyleSet {\n container?: CSSProperties;\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\n}\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\ninterface DisplayTextResult {\n text: string;\n unitText?: string;\n position?: UnitPosition;\n unitStyle?: UnitStyle;\n}\n\ntype DisplayTextFormatter = (\n value: number,\n unit?: string\n) => DisplayTextResult;\n\n\ninterface LatestDataWidgetProps {\n client: AnedyaClient;\n nodeId: string;\n variable: string;\n title?: string;\n unit?: string;\n styles?: StyleSet;\n colorRange?: typeof defaultColorRanges;\n colorRangeCallback?: (value: number, defaultColor: string) => string;\n fontFamily? : string;\n displayText?: DisplayTextFormatter;\n onStyleChange?:(value:number)=>{}\n}\n\nexport const LatestDataWidget: React.FC = React.memo((\n {\n client,\n nodeId,\n variable,\n title,\n unit,\n styles = {},\n colorRange,\n colorRangeCallback,\n displayText,\n onStyleChange\n } \n) => {\n return (\n <>\n \n \n \n \n );\n}, \n(prev, next) => JSON.stringify(prev) === JSON.stringify(next))\n","export default function ascending(a, b) {\n return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n","export default function descending(a, b) {\n return a == null || b == null ? NaN\n : b < a ? -1\n : b > a ? 1\n : b >= a ? 0\n : NaN;\n}\n","import ascending from \"./ascending.js\";\nimport descending from \"./descending.js\";\n\nexport default function bisector(f) {\n let compare1, compare2, delta;\n\n // If an accessor is specified, promote it to a comparator. In this case we\n // can test whether the search value is (self-) comparable. We can’t do this\n // for a comparator (except for specific, known comparators) because we can’t\n // tell if the comparator is symmetric, and an asymmetric comparator can’t be\n // used to test whether a single value is comparable.\n if (f.length !== 2) {\n compare1 = ascending;\n compare2 = (d, x) => ascending(f(d), x);\n delta = (d, x) => f(d) - x;\n } else {\n compare1 = f === ascending || f === descending ? f : zero;\n compare2 = f;\n delta = f;\n }\n\n function left(a, x, lo = 0, hi = a.length) {\n if (lo < hi) {\n if (compare1(x, x) !== 0) return hi;\n do {\n const mid = (lo + hi) >>> 1;\n if (compare2(a[mid], x) < 0) lo = mid + 1;\n else hi = mid;\n } while (lo < hi);\n }\n return lo;\n }\n\n function right(a, x, lo = 0, hi = a.length) {\n if (lo < hi) {\n if (compare1(x, x) !== 0) return hi;\n do {\n const mid = (lo + hi) >>> 1;\n if (compare2(a[mid], x) <= 0) lo = mid + 1;\n else hi = mid;\n } while (lo < hi);\n }\n return lo;\n }\n\n function center(a, x, lo = 0, hi = a.length) {\n const i = left(a, x, lo, hi - 1);\n return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;\n }\n\n return {left, center, right};\n}\n\nfunction zero() {\n return 0;\n}\n","import ascending from \"./ascending.js\";\nimport bisector from \"./bisector.js\";\nimport number from \"./number.js\";\n\nconst ascendingBisect = bisector(ascending);\nexport const bisectRight = ascendingBisect.right;\nexport const bisectLeft = ascendingBisect.left;\nexport const bisectCenter = bisector(number).center;\nexport default bisectRight;\n","export default function number(x) {\n return x === null ? NaN : +x;\n}\n\nexport function* numbers(values, valueof) {\n if (valueof === undefined) {\n for (let value of values) {\n if (value != null && (value = +value) >= value) {\n yield value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null && (value = +value) >= value) {\n yield value;\n }\n }\n }\n}\n","const e10 = Math.sqrt(50),\n e5 = Math.sqrt(10),\n e2 = Math.sqrt(2);\n\nfunction tickSpec(start, stop, count) {\n const step = (stop - start) / Math.max(0, count),\n power = Math.floor(Math.log10(step)),\n error = step / Math.pow(10, power),\n factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;\n let i1, i2, inc;\n if (power < 0) {\n inc = Math.pow(10, -power) / factor;\n i1 = Math.round(start * inc);\n i2 = Math.round(stop * inc);\n if (i1 / inc < start) ++i1;\n if (i2 / inc > stop) --i2;\n inc = -inc;\n } else {\n inc = Math.pow(10, power) * factor;\n i1 = Math.round(start / inc);\n i2 = Math.round(stop / inc);\n if (i1 * inc < start) ++i1;\n if (i2 * inc > stop) --i2;\n }\n if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);\n return [i1, i2, inc];\n}\n\nexport default function ticks(start, stop, count) {\n stop = +stop, start = +start, count = +count;\n if (!(count > 0)) return [];\n if (start === stop) return [start];\n const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);\n if (!(i2 >= i1)) return [];\n const n = i2 - i1 + 1, ticks = new Array(n);\n if (reverse) {\n if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) / -inc;\n else for (let i = 0; i < n; ++i) ticks[i] = (i2 - i) * inc;\n } else {\n if (inc < 0) for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) / -inc;\n else for (let i = 0; i < n; ++i) ticks[i] = (i1 + i) * inc;\n }\n return ticks;\n}\n\nexport function tickIncrement(start, stop, count) {\n stop = +stop, start = +start, count = +count;\n return tickSpec(start, stop, count)[2];\n}\n\nexport function tickStep(start, stop, count) {\n stop = +stop, start = +start, count = +count;\n const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);\n return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);\n}\n","export default function(x) {\n return x;\n}\n","import identity from \"./identity.js\";\n\nvar top = 1,\n right = 2,\n bottom = 3,\n left = 4,\n epsilon = 1e-6;\n\nfunction translateX(x) {\n return \"translate(\" + x + \",0)\";\n}\n\nfunction translateY(y) {\n return \"translate(0,\" + y + \")\";\n}\n\nfunction number(scale) {\n return d => +scale(d);\n}\n\nfunction center(scale, offset) {\n offset = Math.max(0, scale.bandwidth() - offset * 2) / 2;\n if (scale.round()) offset = Math.round(offset);\n return d => +scale(d) + offset;\n}\n\nfunction entering() {\n return !this.__axis;\n}\n\nfunction axis(orient, scale) {\n var tickArguments = [],\n tickValues = null,\n tickFormat = null,\n tickSizeInner = 6,\n tickSizeOuter = 6,\n tickPadding = 3,\n offset = typeof window !== \"undefined\" && window.devicePixelRatio > 1 ? 0 : 0.5,\n k = orient === top || orient === left ? -1 : 1,\n x = orient === left || orient === right ? \"x\" : \"y\",\n transform = orient === top || orient === bottom ? translateX : translateY;\n\n function axis(context) {\n var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,\n format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity) : tickFormat,\n spacing = Math.max(tickSizeInner, 0) + tickPadding,\n range = scale.range(),\n range0 = +range[0] + offset,\n range1 = +range[range.length - 1] + offset,\n position = (scale.bandwidth ? center : number)(scale.copy(), offset),\n selection = context.selection ? context.selection() : context,\n path = selection.selectAll(\".domain\").data([null]),\n tick = selection.selectAll(\".tick\").data(values, scale).order(),\n tickExit = tick.exit(),\n tickEnter = tick.enter().append(\"g\").attr(\"class\", \"tick\"),\n line = tick.select(\"line\"),\n text = tick.select(\"text\");\n\n path = path.merge(path.enter().insert(\"path\", \".tick\")\n .attr(\"class\", \"domain\")\n .attr(\"stroke\", \"currentColor\"));\n\n tick = tick.merge(tickEnter);\n\n line = line.merge(tickEnter.append(\"line\")\n .attr(\"stroke\", \"currentColor\")\n .attr(x + \"2\", k * tickSizeInner));\n\n text = text.merge(tickEnter.append(\"text\")\n .attr(\"fill\", \"currentColor\")\n .attr(x, k * spacing)\n .attr(\"dy\", orient === top ? \"0em\" : orient === bottom ? \"0.71em\" : \"0.32em\"));\n\n if (context !== selection) {\n path = path.transition(context);\n tick = tick.transition(context);\n line = line.transition(context);\n text = text.transition(context);\n\n tickExit = tickExit.transition(context)\n .attr(\"opacity\", epsilon)\n .attr(\"transform\", function(d) { return isFinite(d = position(d)) ? transform(d + offset) : this.getAttribute(\"transform\"); });\n\n tickEnter\n .attr(\"opacity\", epsilon)\n .attr(\"transform\", function(d) { var p = this.parentNode.__axis; return transform((p && isFinite(p = p(d)) ? p : position(d)) + offset); });\n }\n\n tickExit.remove();\n\n path\n .attr(\"d\", orient === left || orient === right\n ? (tickSizeOuter ? \"M\" + k * tickSizeOuter + \",\" + range0 + \"H\" + offset + \"V\" + range1 + \"H\" + k * tickSizeOuter : \"M\" + offset + \",\" + range0 + \"V\" + range1)\n : (tickSizeOuter ? \"M\" + range0 + \",\" + k * tickSizeOuter + \"V\" + offset + \"H\" + range1 + \"V\" + k * tickSizeOuter : \"M\" + range0 + \",\" + offset + \"H\" + range1));\n\n tick\n .attr(\"opacity\", 1)\n .attr(\"transform\", function(d) { return transform(position(d) + offset); });\n\n line\n .attr(x + \"2\", k * tickSizeInner);\n\n text\n .attr(x, k * spacing)\n .text(format);\n\n selection.filter(entering)\n .attr(\"fill\", \"none\")\n .attr(\"font-size\", 10)\n .attr(\"font-family\", \"sans-serif\")\n .attr(\"text-anchor\", orient === right ? \"start\" : orient === left ? \"end\" : \"middle\");\n\n selection\n .each(function() { this.__axis = position; });\n }\n\n axis.scale = function(_) {\n return arguments.length ? (scale = _, axis) : scale;\n };\n\n axis.ticks = function() {\n return tickArguments = Array.from(arguments), axis;\n };\n\n axis.tickArguments = function(_) {\n return arguments.length ? (tickArguments = _ == null ? [] : Array.from(_), axis) : tickArguments.slice();\n };\n\n axis.tickValues = function(_) {\n return arguments.length ? (tickValues = _ == null ? null : Array.from(_), axis) : tickValues && tickValues.slice();\n };\n\n axis.tickFormat = function(_) {\n return arguments.length ? (tickFormat = _, axis) : tickFormat;\n };\n\n axis.tickSize = function(_) {\n return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;\n };\n\n axis.tickSizeInner = function(_) {\n return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;\n };\n\n axis.tickSizeOuter = function(_) {\n return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;\n };\n\n axis.tickPadding = function(_) {\n return arguments.length ? (tickPadding = +_, axis) : tickPadding;\n };\n\n axis.offset = function(_) {\n return arguments.length ? (offset = +_, axis) : offset;\n };\n\n return axis;\n}\n\nexport function axisTop(scale) {\n return axis(top, scale);\n}\n\nexport function axisRight(scale) {\n return axis(right, scale);\n}\n\nexport function axisBottom(scale) {\n return axis(bottom, scale);\n}\n\nexport function axisLeft(scale) {\n return axis(left, scale);\n}\n","var noop = {value: () => {}};\n\nfunction dispatch() {\n for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {\n if (!(t = arguments[i] + \"\") || (t in _) || /[\\s.]/.test(t)) throw new Error(\"illegal type: \" + t);\n _[t] = [];\n }\n return new Dispatch(_);\n}\n\nfunction Dispatch(_) {\n this._ = _;\n}\n\nfunction parseTypenames(typenames, types) {\n return typenames.trim().split(/^|\\s+/).map(function(t) {\n var name = \"\", i = t.indexOf(\".\");\n if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);\n if (t && !types.hasOwnProperty(t)) throw new Error(\"unknown type: \" + t);\n return {type: t, name: name};\n });\n}\n\nDispatch.prototype = dispatch.prototype = {\n constructor: Dispatch,\n on: function(typename, callback) {\n var _ = this._,\n T = parseTypenames(typename + \"\", _),\n t,\n i = -1,\n n = T.length;\n\n // If no callback was specified, return the callback of the given type and name.\n if (arguments.length < 2) {\n while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;\n return;\n }\n\n // If a type was specified, set the callback for the given type and name.\n // Otherwise, if a null callback was specified, remove callbacks of the given name.\n if (callback != null && typeof callback !== \"function\") throw new Error(\"invalid callback: \" + callback);\n while (++i < n) {\n if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);\n else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);\n }\n\n return this;\n },\n copy: function() {\n var copy = {}, _ = this._;\n for (var t in _) copy[t] = _[t].slice();\n return new Dispatch(copy);\n },\n call: function(type, that) {\n if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];\n if (!this._.hasOwnProperty(type)) throw new Error(\"unknown type: \" + type);\n for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);\n },\n apply: function(type, that, args) {\n if (!this._.hasOwnProperty(type)) throw new Error(\"unknown type: \" + type);\n for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);\n }\n};\n\nfunction get(type, name) {\n for (var i = 0, n = type.length, c; i < n; ++i) {\n if ((c = type[i]).name === name) {\n return c.value;\n }\n }\n}\n\nfunction set(type, name, callback) {\n for (var i = 0, n = type.length; i < n; ++i) {\n if (type[i].name === name) {\n type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));\n break;\n }\n }\n if (callback != null) type.push({name: name, value: callback});\n return type;\n}\n\nexport default dispatch;\n","export var xhtml = \"http://www.w3.org/1999/xhtml\";\n\nexport default {\n svg: \"http://www.w3.org/2000/svg\",\n xhtml: xhtml,\n xlink: \"http://www.w3.org/1999/xlink\",\n xml: \"http://www.w3.org/XML/1998/namespace\",\n xmlns: \"http://www.w3.org/2000/xmlns/\"\n};\n","import namespaces from \"./namespaces.js\";\n\nexport default function(name) {\n var prefix = name += \"\", i = prefix.indexOf(\":\");\n if (i >= 0 && (prefix = name.slice(0, i)) !== \"xmlns\") name = name.slice(i + 1);\n return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins\n}\n","import namespace from \"./namespace.js\";\nimport {xhtml} from \"./namespaces.js\";\n\nfunction creatorInherit(name) {\n return function() {\n var document = this.ownerDocument,\n uri = this.namespaceURI;\n return uri === xhtml && document.documentElement.namespaceURI === xhtml\n ? document.createElement(name)\n : document.createElementNS(uri, name);\n };\n}\n\nfunction creatorFixed(fullname) {\n return function() {\n return this.ownerDocument.createElementNS(fullname.space, fullname.local);\n };\n}\n\nexport default function(name) {\n var fullname = namespace(name);\n return (fullname.local\n ? creatorFixed\n : creatorInherit)(fullname);\n}\n","function none() {}\n\nexport default function(selector) {\n return selector == null ? none : function() {\n return this.querySelector(selector);\n };\n}\n","function empty() {\n return [];\n}\n\nexport default function(selector) {\n return selector == null ? empty : function() {\n return this.querySelectorAll(selector);\n };\n}\n","import {Selection} from \"./index.js\";\nimport array from \"../array.js\";\nimport selectorAll from \"../selectorAll.js\";\n\nfunction arrayAll(select) {\n return function() {\n return array(select.apply(this, arguments));\n };\n}\n\nexport default function(select) {\n if (typeof select === \"function\") select = arrayAll(select);\n else select = selectorAll(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n subgroups.push(select.call(node, node.__data__, i, group));\n parents.push(node);\n }\n }\n }\n\n return new Selection(subgroups, parents);\n}\n","// Given something array like (or null), returns something that is strictly an\n// array. This is used to ensure that array-like objects passed to d3.selectAll\n// or selection.selectAll are converted into proper arrays when creating a\n// selection; we don’t ever want to create a selection backed by a live\n// HTMLCollection or NodeList. However, note that selection.selectAll will use a\n// static NodeList as a group, since it safely derived from querySelectorAll.\nexport default function array(x) {\n return x == null ? [] : Array.isArray(x) ? x : Array.from(x);\n}\n","export default function(selector) {\n return function() {\n return this.matches(selector);\n };\n}\n\nexport function childMatcher(selector) {\n return function(node) {\n return node.matches(selector);\n };\n}\n\n","import {childMatcher} from \"../matcher.js\";\n\nvar find = Array.prototype.find;\n\nfunction childFind(match) {\n return function() {\n return find.call(this.children, match);\n };\n}\n\nfunction childFirst() {\n return this.firstElementChild;\n}\n\nexport default function(match) {\n return this.select(match == null ? childFirst\n : childFind(typeof match === \"function\" ? match : childMatcher(match)));\n}\n","import {childMatcher} from \"../matcher.js\";\n\nvar filter = Array.prototype.filter;\n\nfunction children() {\n return Array.from(this.children);\n}\n\nfunction childrenFilter(match) {\n return function() {\n return filter.call(this.children, match);\n };\n}\n\nexport default function(match) {\n return this.selectAll(match == null ? children\n : childrenFilter(typeof match === \"function\" ? match : childMatcher(match)));\n}\n","export default function(update) {\n return new Array(update.length);\n}\n","import sparse from \"./sparse.js\";\nimport {Selection} from \"./index.js\";\n\nexport default function() {\n return new Selection(this._enter || this._groups.map(sparse), this._parents);\n}\n\nexport function EnterNode(parent, datum) {\n this.ownerDocument = parent.ownerDocument;\n this.namespaceURI = parent.namespaceURI;\n this._next = null;\n this._parent = parent;\n this.__data__ = datum;\n}\n\nEnterNode.prototype = {\n constructor: EnterNode,\n appendChild: function(child) { return this._parent.insertBefore(child, this._next); },\n insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },\n querySelector: function(selector) { return this._parent.querySelector(selector); },\n querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }\n};\n","import {Selection} from \"./index.js\";\nimport {EnterNode} from \"./enter.js\";\nimport constant from \"../constant.js\";\n\nfunction bindIndex(parent, group, enter, update, exit, data) {\n var i = 0,\n node,\n groupLength = group.length,\n dataLength = data.length;\n\n // Put any non-null nodes that fit into update.\n // Put any null nodes into enter.\n // Put any remaining data into enter.\n for (; i < dataLength; ++i) {\n if (node = group[i]) {\n node.__data__ = data[i];\n update[i] = node;\n } else {\n enter[i] = new EnterNode(parent, data[i]);\n }\n }\n\n // Put any non-null nodes that don’t fit into exit.\n for (; i < groupLength; ++i) {\n if (node = group[i]) {\n exit[i] = node;\n }\n }\n}\n\nfunction bindKey(parent, group, enter, update, exit, data, key) {\n var i,\n node,\n nodeByKeyValue = new Map,\n groupLength = group.length,\n dataLength = data.length,\n keyValues = new Array(groupLength),\n keyValue;\n\n // Compute the key for each node.\n // If multiple nodes have the same key, the duplicates are added to exit.\n for (i = 0; i < groupLength; ++i) {\n if (node = group[i]) {\n keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + \"\";\n if (nodeByKeyValue.has(keyValue)) {\n exit[i] = node;\n } else {\n nodeByKeyValue.set(keyValue, node);\n }\n }\n }\n\n // Compute the key for each datum.\n // If there a node associated with this key, join and add it to update.\n // If there is not (or the key is a duplicate), add it to enter.\n for (i = 0; i < dataLength; ++i) {\n keyValue = key.call(parent, data[i], i, data) + \"\";\n if (node = nodeByKeyValue.get(keyValue)) {\n update[i] = node;\n node.__data__ = data[i];\n nodeByKeyValue.delete(keyValue);\n } else {\n enter[i] = new EnterNode(parent, data[i]);\n }\n }\n\n // Add any remaining nodes that were not bound to data to exit.\n for (i = 0; i < groupLength; ++i) {\n if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) {\n exit[i] = node;\n }\n }\n}\n\nfunction datum(node) {\n return node.__data__;\n}\n\nexport default function(value, key) {\n if (!arguments.length) return Array.from(this, datum);\n\n var bind = key ? bindKey : bindIndex,\n parents = this._parents,\n groups = this._groups;\n\n if (typeof value !== \"function\") value = constant(value);\n\n for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {\n var parent = parents[j],\n group = groups[j],\n groupLength = group.length,\n data = arraylike(value.call(parent, parent && parent.__data__, j, parents)),\n dataLength = data.length,\n enterGroup = enter[j] = new Array(dataLength),\n updateGroup = update[j] = new Array(dataLength),\n exitGroup = exit[j] = new Array(groupLength);\n\n bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);\n\n // Now connect the enter nodes to their following update node, such that\n // appendChild can insert the materialized enter node before this node,\n // rather than at the end of the parent node.\n for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {\n if (previous = enterGroup[i0]) {\n if (i0 >= i1) i1 = i0 + 1;\n while (!(next = updateGroup[i1]) && ++i1 < dataLength);\n previous._next = next || null;\n }\n }\n }\n\n update = new Selection(update, parents);\n update._enter = enter;\n update._exit = exit;\n return update;\n}\n\n// Given some data, this returns an array-like view of it: an object that\n// exposes a length property and allows numeric indexing. Note that unlike\n// selectAll, this isn’t worried about β€œlive” collections because the resulting\n// array will only be used briefly while data is being bound. (It is possible to\n// cause the data to change while iterating by using a key function, but please\n// don’t; we’d rather avoid a gratuitous copy.)\nfunction arraylike(data) {\n return typeof data === \"object\" && \"length\" in data\n ? data // Array, TypedArray, NodeList, array-like\n : Array.from(data); // Map, Set, iterable, string, or anything else\n}\n","import {Selection} from \"./index.js\";\n\nexport default function(compare) {\n if (!compare) compare = ascending;\n\n function compareNode(a, b) {\n return a && b ? compare(a.__data__, b.__data__) : !a - !b;\n }\n\n for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n sortgroup[i] = node;\n }\n }\n sortgroup.sort(compareNode);\n }\n\n return new Selection(sortgroups, this._parents).order();\n}\n\nfunction ascending(a, b) {\n return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n","import namespace from \"../namespace.js\";\n\nfunction attrRemove(name) {\n return function() {\n this.removeAttribute(name);\n };\n}\n\nfunction attrRemoveNS(fullname) {\n return function() {\n this.removeAttributeNS(fullname.space, fullname.local);\n };\n}\n\nfunction attrConstant(name, value) {\n return function() {\n this.setAttribute(name, value);\n };\n}\n\nfunction attrConstantNS(fullname, value) {\n return function() {\n this.setAttributeNS(fullname.space, fullname.local, value);\n };\n}\n\nfunction attrFunction(name, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) this.removeAttribute(name);\n else this.setAttribute(name, v);\n };\n}\n\nfunction attrFunctionNS(fullname, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) this.removeAttributeNS(fullname.space, fullname.local);\n else this.setAttributeNS(fullname.space, fullname.local, v);\n };\n}\n\nexport default function(name, value) {\n var fullname = namespace(name);\n\n if (arguments.length < 2) {\n var node = this.node();\n return fullname.local\n ? node.getAttributeNS(fullname.space, fullname.local)\n : node.getAttribute(fullname);\n }\n\n return this.each((value == null\n ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === \"function\"\n ? (fullname.local ? attrFunctionNS : attrFunction)\n : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));\n}\n","export default function(node) {\n return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node\n || (node.document && node) // node is a Window\n || node.defaultView; // node is a Document\n}\n","import defaultView from \"../window.js\";\n\nfunction styleRemove(name) {\n return function() {\n this.style.removeProperty(name);\n };\n}\n\nfunction styleConstant(name, value, priority) {\n return function() {\n this.style.setProperty(name, value, priority);\n };\n}\n\nfunction styleFunction(name, value, priority) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) this.style.removeProperty(name);\n else this.style.setProperty(name, v, priority);\n };\n}\n\nexport default function(name, value, priority) {\n return arguments.length > 1\n ? this.each((value == null\n ? styleRemove : typeof value === \"function\"\n ? styleFunction\n : styleConstant)(name, value, priority == null ? \"\" : priority))\n : styleValue(this.node(), name);\n}\n\nexport function styleValue(node, name) {\n return node.style.getPropertyValue(name)\n || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);\n}\n","function propertyRemove(name) {\n return function() {\n delete this[name];\n };\n}\n\nfunction propertyConstant(name, value) {\n return function() {\n this[name] = value;\n };\n}\n\nfunction propertyFunction(name, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (v == null) delete this[name];\n else this[name] = v;\n };\n}\n\nexport default function(name, value) {\n return arguments.length > 1\n ? this.each((value == null\n ? propertyRemove : typeof value === \"function\"\n ? propertyFunction\n : propertyConstant)(name, value))\n : this.node()[name];\n}\n","function classArray(string) {\n return string.trim().split(/^|\\s+/);\n}\n\nfunction classList(node) {\n return node.classList || new ClassList(node);\n}\n\nfunction ClassList(node) {\n this._node = node;\n this._names = classArray(node.getAttribute(\"class\") || \"\");\n}\n\nClassList.prototype = {\n add: function(name) {\n var i = this._names.indexOf(name);\n if (i < 0) {\n this._names.push(name);\n this._node.setAttribute(\"class\", this._names.join(\" \"));\n }\n },\n remove: function(name) {\n var i = this._names.indexOf(name);\n if (i >= 0) {\n this._names.splice(i, 1);\n this._node.setAttribute(\"class\", this._names.join(\" \"));\n }\n },\n contains: function(name) {\n return this._names.indexOf(name) >= 0;\n }\n};\n\nfunction classedAdd(node, names) {\n var list = classList(node), i = -1, n = names.length;\n while (++i < n) list.add(names[i]);\n}\n\nfunction classedRemove(node, names) {\n var list = classList(node), i = -1, n = names.length;\n while (++i < n) list.remove(names[i]);\n}\n\nfunction classedTrue(names) {\n return function() {\n classedAdd(this, names);\n };\n}\n\nfunction classedFalse(names) {\n return function() {\n classedRemove(this, names);\n };\n}\n\nfunction classedFunction(names, value) {\n return function() {\n (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);\n };\n}\n\nexport default function(name, value) {\n var names = classArray(name + \"\");\n\n if (arguments.length < 2) {\n var list = classList(this.node()), i = -1, n = names.length;\n while (++i < n) if (!list.contains(names[i])) return false;\n return true;\n }\n\n return this.each((typeof value === \"function\"\n ? classedFunction : value\n ? classedTrue\n : classedFalse)(names, value));\n}\n","function textRemove() {\n this.textContent = \"\";\n}\n\nfunction textConstant(value) {\n return function() {\n this.textContent = value;\n };\n}\n\nfunction textFunction(value) {\n return function() {\n var v = value.apply(this, arguments);\n this.textContent = v == null ? \"\" : v;\n };\n}\n\nexport default function(value) {\n return arguments.length\n ? this.each(value == null\n ? textRemove : (typeof value === \"function\"\n ? textFunction\n : textConstant)(value))\n : this.node().textContent;\n}\n","function htmlRemove() {\n this.innerHTML = \"\";\n}\n\nfunction htmlConstant(value) {\n return function() {\n this.innerHTML = value;\n };\n}\n\nfunction htmlFunction(value) {\n return function() {\n var v = value.apply(this, arguments);\n this.innerHTML = v == null ? \"\" : v;\n };\n}\n\nexport default function(value) {\n return arguments.length\n ? this.each(value == null\n ? htmlRemove : (typeof value === \"function\"\n ? htmlFunction\n : htmlConstant)(value))\n : this.node().innerHTML;\n}\n","function raise() {\n if (this.nextSibling) this.parentNode.appendChild(this);\n}\n\nexport default function() {\n return this.each(raise);\n}\n","function lower() {\n if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);\n}\n\nexport default function() {\n return this.each(lower);\n}\n","import creator from \"../creator.js\";\nimport selector from \"../selector.js\";\n\nfunction constantNull() {\n return null;\n}\n\nexport default function(name, before) {\n var create = typeof name === \"function\" ? name : creator(name),\n select = before == null ? constantNull : typeof before === \"function\" ? before : selector(before);\n return this.select(function() {\n return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);\n });\n}\n","function remove() {\n var parent = this.parentNode;\n if (parent) parent.removeChild(this);\n}\n\nexport default function() {\n return this.each(remove);\n}\n","function selection_cloneShallow() {\n var clone = this.cloneNode(false), parent = this.parentNode;\n return parent ? parent.insertBefore(clone, this.nextSibling) : clone;\n}\n\nfunction selection_cloneDeep() {\n var clone = this.cloneNode(true), parent = this.parentNode;\n return parent ? parent.insertBefore(clone, this.nextSibling) : clone;\n}\n\nexport default function(deep) {\n return this.select(deep ? selection_cloneDeep : selection_cloneShallow);\n}\n","function contextListener(listener) {\n return function(event) {\n listener.call(this, event, this.__data__);\n };\n}\n\nfunction parseTypenames(typenames) {\n return typenames.trim().split(/^|\\s+/).map(function(t) {\n var name = \"\", i = t.indexOf(\".\");\n if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);\n return {type: t, name: name};\n });\n}\n\nfunction onRemove(typename) {\n return function() {\n var on = this.__on;\n if (!on) return;\n for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {\n if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {\n this.removeEventListener(o.type, o.listener, o.options);\n } else {\n on[++i] = o;\n }\n }\n if (++i) on.length = i;\n else delete this.__on;\n };\n}\n\nfunction onAdd(typename, value, options) {\n return function() {\n var on = this.__on, o, listener = contextListener(value);\n if (on) for (var j = 0, m = on.length; j < m; ++j) {\n if ((o = on[j]).type === typename.type && o.name === typename.name) {\n this.removeEventListener(o.type, o.listener, o.options);\n this.addEventListener(o.type, o.listener = listener, o.options = options);\n o.value = value;\n return;\n }\n }\n this.addEventListener(typename.type, listener, options);\n o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options};\n if (!on) this.__on = [o];\n else on.push(o);\n };\n}\n\nexport default function(typename, value, options) {\n var typenames = parseTypenames(typename + \"\"), i, n = typenames.length, t;\n\n if (arguments.length < 2) {\n var on = this.node().__on;\n if (on) for (var j = 0, m = on.length, o; j < m; ++j) {\n for (i = 0, o = on[j]; i < n; ++i) {\n if ((t = typenames[i]).type === o.type && t.name === o.name) {\n return o.value;\n }\n }\n }\n return;\n }\n\n on = value ? onAdd : onRemove;\n for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));\n return this;\n}\n","import defaultView from \"../window.js\";\n\nfunction dispatchEvent(node, type, params) {\n var window = defaultView(node),\n event = window.CustomEvent;\n\n if (typeof event === \"function\") {\n event = new event(type, params);\n } else {\n event = window.document.createEvent(\"Event\");\n if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;\n else event.initEvent(type, false, false);\n }\n\n node.dispatchEvent(event);\n}\n\nfunction dispatchConstant(type, params) {\n return function() {\n return dispatchEvent(this, type, params);\n };\n}\n\nfunction dispatchFunction(type, params) {\n return function() {\n return dispatchEvent(this, type, params.apply(this, arguments));\n };\n}\n\nexport default function(type, params) {\n return this.each((typeof params === \"function\"\n ? dispatchFunction\n : dispatchConstant)(type, params));\n}\n","import selection_select from \"./select.js\";\nimport selection_selectAll from \"./selectAll.js\";\nimport selection_selectChild from \"./selectChild.js\";\nimport selection_selectChildren from \"./selectChildren.js\";\nimport selection_filter from \"./filter.js\";\nimport selection_data from \"./data.js\";\nimport selection_enter from \"./enter.js\";\nimport selection_exit from \"./exit.js\";\nimport selection_join from \"./join.js\";\nimport selection_merge from \"./merge.js\";\nimport selection_order from \"./order.js\";\nimport selection_sort from \"./sort.js\";\nimport selection_call from \"./call.js\";\nimport selection_nodes from \"./nodes.js\";\nimport selection_node from \"./node.js\";\nimport selection_size from \"./size.js\";\nimport selection_empty from \"./empty.js\";\nimport selection_each from \"./each.js\";\nimport selection_attr from \"./attr.js\";\nimport selection_style from \"./style.js\";\nimport selection_property from \"./property.js\";\nimport selection_classed from \"./classed.js\";\nimport selection_text from \"./text.js\";\nimport selection_html from \"./html.js\";\nimport selection_raise from \"./raise.js\";\nimport selection_lower from \"./lower.js\";\nimport selection_append from \"./append.js\";\nimport selection_insert from \"./insert.js\";\nimport selection_remove from \"./remove.js\";\nimport selection_clone from \"./clone.js\";\nimport selection_datum from \"./datum.js\";\nimport selection_on from \"./on.js\";\nimport selection_dispatch from \"./dispatch.js\";\nimport selection_iterator from \"./iterator.js\";\n\nexport var root = [null];\n\nexport function Selection(groups, parents) {\n this._groups = groups;\n this._parents = parents;\n}\n\nfunction selection() {\n return new Selection([[document.documentElement]], root);\n}\n\nfunction selection_selection() {\n return this;\n}\n\nSelection.prototype = selection.prototype = {\n constructor: Selection,\n select: selection_select,\n selectAll: selection_selectAll,\n selectChild: selection_selectChild,\n selectChildren: selection_selectChildren,\n filter: selection_filter,\n data: selection_data,\n enter: selection_enter,\n exit: selection_exit,\n join: selection_join,\n merge: selection_merge,\n selection: selection_selection,\n order: selection_order,\n sort: selection_sort,\n call: selection_call,\n nodes: selection_nodes,\n node: selection_node,\n size: selection_size,\n empty: selection_empty,\n each: selection_each,\n attr: selection_attr,\n style: selection_style,\n property: selection_property,\n classed: selection_classed,\n text: selection_text,\n html: selection_html,\n raise: selection_raise,\n lower: selection_lower,\n append: selection_append,\n insert: selection_insert,\n remove: selection_remove,\n clone: selection_clone,\n datum: selection_datum,\n on: selection_on,\n dispatch: selection_dispatch,\n [Symbol.iterator]: selection_iterator\n};\n\nexport default selection;\n","import {Selection, root} from \"./selection/index.js\";\n\nexport default function(selector) {\n return typeof selector === \"string\"\n ? new Selection([[document.querySelector(selector)]], [document.documentElement])\n : new Selection([[selector]], root);\n}\n","export default function(constructor, factory, prototype) {\n constructor.prototype = factory.prototype = prototype;\n prototype.constructor = constructor;\n}\n\nexport function extend(parent, definition) {\n var prototype = Object.create(parent.prototype);\n for (var key in definition) prototype[key] = definition[key];\n return prototype;\n}\n","import define, {extend} from \"./define.js\";\n\nexport function Color() {}\n\nexport var darker = 0.7;\nexport var brighter = 1 / darker;\n\nvar reI = \"\\\\s*([+-]?\\\\d+)\\\\s*\",\n reN = \"\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+(?:[eE][+-]?\\\\d+)?)\\\\s*\",\n reP = \"\\\\s*([+-]?(?:\\\\d*\\\\.)?\\\\d+(?:[eE][+-]?\\\\d+)?)%\\\\s*\",\n reHex = /^#([0-9a-f]{3,8})$/,\n reRgbInteger = new RegExp(`^rgb\\\\(${reI},${reI},${reI}\\\\)$`),\n reRgbPercent = new RegExp(`^rgb\\\\(${reP},${reP},${reP}\\\\)$`),\n reRgbaInteger = new RegExp(`^rgba\\\\(${reI},${reI},${reI},${reN}\\\\)$`),\n reRgbaPercent = new RegExp(`^rgba\\\\(${reP},${reP},${reP},${reN}\\\\)$`),\n reHslPercent = new RegExp(`^hsl\\\\(${reN},${reP},${reP}\\\\)$`),\n reHslaPercent = new RegExp(`^hsla\\\\(${reN},${reP},${reP},${reN}\\\\)$`);\n\nvar named = {\n aliceblue: 0xf0f8ff,\n antiquewhite: 0xfaebd7,\n aqua: 0x00ffff,\n aquamarine: 0x7fffd4,\n azure: 0xf0ffff,\n beige: 0xf5f5dc,\n bisque: 0xffe4c4,\n black: 0x000000,\n blanchedalmond: 0xffebcd,\n blue: 0x0000ff,\n blueviolet: 0x8a2be2,\n brown: 0xa52a2a,\n burlywood: 0xdeb887,\n cadetblue: 0x5f9ea0,\n chartreuse: 0x7fff00,\n chocolate: 0xd2691e,\n coral: 0xff7f50,\n cornflowerblue: 0x6495ed,\n cornsilk: 0xfff8dc,\n crimson: 0xdc143c,\n cyan: 0x00ffff,\n darkblue: 0x00008b,\n darkcyan: 0x008b8b,\n darkgoldenrod: 0xb8860b,\n darkgray: 0xa9a9a9,\n darkgreen: 0x006400,\n darkgrey: 0xa9a9a9,\n darkkhaki: 0xbdb76b,\n darkmagenta: 0x8b008b,\n darkolivegreen: 0x556b2f,\n darkorange: 0xff8c00,\n darkorchid: 0x9932cc,\n darkred: 0x8b0000,\n darksalmon: 0xe9967a,\n darkseagreen: 0x8fbc8f,\n darkslateblue: 0x483d8b,\n darkslategray: 0x2f4f4f,\n darkslategrey: 0x2f4f4f,\n darkturquoise: 0x00ced1,\n darkviolet: 0x9400d3,\n deeppink: 0xff1493,\n deepskyblue: 0x00bfff,\n dimgray: 0x696969,\n dimgrey: 0x696969,\n dodgerblue: 0x1e90ff,\n firebrick: 0xb22222,\n floralwhite: 0xfffaf0,\n forestgreen: 0x228b22,\n fuchsia: 0xff00ff,\n gainsboro: 0xdcdcdc,\n ghostwhite: 0xf8f8ff,\n gold: 0xffd700,\n goldenrod: 0xdaa520,\n gray: 0x808080,\n green: 0x008000,\n greenyellow: 0xadff2f,\n grey: 0x808080,\n honeydew: 0xf0fff0,\n hotpink: 0xff69b4,\n indianred: 0xcd5c5c,\n indigo: 0x4b0082,\n ivory: 0xfffff0,\n khaki: 0xf0e68c,\n lavender: 0xe6e6fa,\n lavenderblush: 0xfff0f5,\n lawngreen: 0x7cfc00,\n lemonchiffon: 0xfffacd,\n lightblue: 0xadd8e6,\n lightcoral: 0xf08080,\n lightcyan: 0xe0ffff,\n lightgoldenrodyellow: 0xfafad2,\n lightgray: 0xd3d3d3,\n lightgreen: 0x90ee90,\n lightgrey: 0xd3d3d3,\n lightpink: 0xffb6c1,\n lightsalmon: 0xffa07a,\n lightseagreen: 0x20b2aa,\n lightskyblue: 0x87cefa,\n lightslategray: 0x778899,\n lightslategrey: 0x778899,\n lightsteelblue: 0xb0c4de,\n lightyellow: 0xffffe0,\n lime: 0x00ff00,\n limegreen: 0x32cd32,\n linen: 0xfaf0e6,\n magenta: 0xff00ff,\n maroon: 0x800000,\n mediumaquamarine: 0x66cdaa,\n mediumblue: 0x0000cd,\n mediumorchid: 0xba55d3,\n mediumpurple: 0x9370db,\n mediumseagreen: 0x3cb371,\n mediumslateblue: 0x7b68ee,\n mediumspringgreen: 0x00fa9a,\n mediumturquoise: 0x48d1cc,\n mediumvioletred: 0xc71585,\n midnightblue: 0x191970,\n mintcream: 0xf5fffa,\n mistyrose: 0xffe4e1,\n moccasin: 0xffe4b5,\n navajowhite: 0xffdead,\n navy: 0x000080,\n oldlace: 0xfdf5e6,\n olive: 0x808000,\n olivedrab: 0x6b8e23,\n orange: 0xffa500,\n orangered: 0xff4500,\n orchid: 0xda70d6,\n palegoldenrod: 0xeee8aa,\n palegreen: 0x98fb98,\n paleturquoise: 0xafeeee,\n palevioletred: 0xdb7093,\n papayawhip: 0xffefd5,\n peachpuff: 0xffdab9,\n peru: 0xcd853f,\n pink: 0xffc0cb,\n plum: 0xdda0dd,\n powderblue: 0xb0e0e6,\n purple: 0x800080,\n rebeccapurple: 0x663399,\n red: 0xff0000,\n rosybrown: 0xbc8f8f,\n royalblue: 0x4169e1,\n saddlebrown: 0x8b4513,\n salmon: 0xfa8072,\n sandybrown: 0xf4a460,\n seagreen: 0x2e8b57,\n seashell: 0xfff5ee,\n sienna: 0xa0522d,\n silver: 0xc0c0c0,\n skyblue: 0x87ceeb,\n slateblue: 0x6a5acd,\n slategray: 0x708090,\n slategrey: 0x708090,\n snow: 0xfffafa,\n springgreen: 0x00ff7f,\n steelblue: 0x4682b4,\n tan: 0xd2b48c,\n teal: 0x008080,\n thistle: 0xd8bfd8,\n tomato: 0xff6347,\n turquoise: 0x40e0d0,\n violet: 0xee82ee,\n wheat: 0xf5deb3,\n white: 0xffffff,\n whitesmoke: 0xf5f5f5,\n yellow: 0xffff00,\n yellowgreen: 0x9acd32\n};\n\ndefine(Color, color, {\n copy(channels) {\n return Object.assign(new this.constructor, this, channels);\n },\n displayable() {\n return this.rgb().displayable();\n },\n hex: color_formatHex, // Deprecated! Use color.formatHex.\n formatHex: color_formatHex,\n formatHex8: color_formatHex8,\n formatHsl: color_formatHsl,\n formatRgb: color_formatRgb,\n toString: color_formatRgb\n});\n\nfunction color_formatHex() {\n return this.rgb().formatHex();\n}\n\nfunction color_formatHex8() {\n return this.rgb().formatHex8();\n}\n\nfunction color_formatHsl() {\n return hslConvert(this).formatHsl();\n}\n\nfunction color_formatRgb() {\n return this.rgb().formatRgb();\n}\n\nexport default function color(format) {\n var m, l;\n format = (format + \"\").trim().toLowerCase();\n return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000\n : l === 3 ? new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) // #f00\n : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000\n : l === 4 ? rgba((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff) // #f000\n : null) // invalid hex\n : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)\n : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)\n : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)\n : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)\n : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)\n : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)\n : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins\n : format === \"transparent\" ? new Rgb(NaN, NaN, NaN, 0)\n : null;\n}\n\nfunction rgbn(n) {\n return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);\n}\n\nfunction rgba(r, g, b, a) {\n if (a <= 0) r = g = b = NaN;\n return new Rgb(r, g, b, a);\n}\n\nexport function rgbConvert(o) {\n if (!(o instanceof Color)) o = color(o);\n if (!o) return new Rgb;\n o = o.rgb();\n return new Rgb(o.r, o.g, o.b, o.opacity);\n}\n\nexport function rgb(r, g, b, opacity) {\n return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);\n}\n\nexport function Rgb(r, g, b, opacity) {\n this.r = +r;\n this.g = +g;\n this.b = +b;\n this.opacity = +opacity;\n}\n\ndefine(Rgb, rgb, extend(Color, {\n brighter(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);\n },\n darker(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);\n },\n rgb() {\n return this;\n },\n clamp() {\n return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));\n },\n displayable() {\n return (-0.5 <= this.r && this.r < 255.5)\n && (-0.5 <= this.g && this.g < 255.5)\n && (-0.5 <= this.b && this.b < 255.5)\n && (0 <= this.opacity && this.opacity <= 1);\n },\n hex: rgb_formatHex, // Deprecated! Use color.formatHex.\n formatHex: rgb_formatHex,\n formatHex8: rgb_formatHex8,\n formatRgb: rgb_formatRgb,\n toString: rgb_formatRgb\n}));\n\nfunction rgb_formatHex() {\n return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;\n}\n\nfunction rgb_formatHex8() {\n return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;\n}\n\nfunction rgb_formatRgb() {\n const a = clampa(this.opacity);\n return `${a === 1 ? \"rgb(\" : \"rgba(\"}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? \")\" : `, ${a})`}`;\n}\n\nfunction clampa(opacity) {\n return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));\n}\n\nfunction clampi(value) {\n return Math.max(0, Math.min(255, Math.round(value) || 0));\n}\n\nfunction hex(value) {\n value = clampi(value);\n return (value < 16 ? \"0\" : \"\") + value.toString(16);\n}\n\nfunction hsla(h, s, l, a) {\n if (a <= 0) h = s = l = NaN;\n else if (l <= 0 || l >= 1) h = s = NaN;\n else if (s <= 0) h = NaN;\n return new Hsl(h, s, l, a);\n}\n\nexport function hslConvert(o) {\n if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);\n if (!(o instanceof Color)) o = color(o);\n if (!o) return new Hsl;\n if (o instanceof Hsl) return o;\n o = o.rgb();\n var r = o.r / 255,\n g = o.g / 255,\n b = o.b / 255,\n min = Math.min(r, g, b),\n max = Math.max(r, g, b),\n h = NaN,\n s = max - min,\n l = (max + min) / 2;\n if (s) {\n if (r === max) h = (g - b) / s + (g < b) * 6;\n else if (g === max) h = (b - r) / s + 2;\n else h = (r - g) / s + 4;\n s /= l < 0.5 ? max + min : 2 - max - min;\n h *= 60;\n } else {\n s = l > 0 && l < 1 ? 0 : h;\n }\n return new Hsl(h, s, l, o.opacity);\n}\n\nexport function hsl(h, s, l, opacity) {\n return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);\n}\n\nfunction Hsl(h, s, l, opacity) {\n this.h = +h;\n this.s = +s;\n this.l = +l;\n this.opacity = +opacity;\n}\n\ndefine(Hsl, hsl, extend(Color, {\n brighter(k) {\n k = k == null ? brighter : Math.pow(brighter, k);\n return new Hsl(this.h, this.s, this.l * k, this.opacity);\n },\n darker(k) {\n k = k == null ? darker : Math.pow(darker, k);\n return new Hsl(this.h, this.s, this.l * k, this.opacity);\n },\n rgb() {\n var h = this.h % 360 + (this.h < 0) * 360,\n s = isNaN(h) || isNaN(this.s) ? 0 : this.s,\n l = this.l,\n m2 = l + (l < 0.5 ? l : 1 - l) * s,\n m1 = 2 * l - m2;\n return new Rgb(\n hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),\n hsl2rgb(h, m1, m2),\n hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),\n this.opacity\n );\n },\n clamp() {\n return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));\n },\n displayable() {\n return (0 <= this.s && this.s <= 1 || isNaN(this.s))\n && (0 <= this.l && this.l <= 1)\n && (0 <= this.opacity && this.opacity <= 1);\n },\n formatHsl() {\n const a = clampa(this.opacity);\n return `${a === 1 ? \"hsl(\" : \"hsla(\"}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? \")\" : `, ${a})`}`;\n }\n}));\n\nfunction clamph(value) {\n value = (value || 0) % 360;\n return value < 0 ? value + 360 : value;\n}\n\nfunction clampt(value) {\n return Math.max(0, Math.min(1, value || 0));\n}\n\n/* From FvD 13.37, CSS Color Module Level 3 */\nfunction hsl2rgb(h, m1, m2) {\n return (h < 60 ? m1 + (m2 - m1) * h / 60\n : h < 180 ? m2\n : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60\n : m1) * 255;\n}\n","import {Selection} from \"./index.js\";\nimport selector from \"../selector.js\";\n\nexport default function(select) {\n if (typeof select !== \"function\") select = selector(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {\n if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {\n if (\"__data__\" in node) subnode.__data__ = node.__data__;\n subgroup[i] = subnode;\n }\n }\n }\n\n return new Selection(subgroups, this._parents);\n}\n","import {Selection} from \"./index.js\";\nimport matcher from \"../matcher.js\";\n\nexport default function(match) {\n if (typeof match !== \"function\") match = matcher(match);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {\n if ((node = group[i]) && match.call(node, node.__data__, i, group)) {\n subgroup.push(node);\n }\n }\n }\n\n return new Selection(subgroups, this._parents);\n}\n","export default function(x) {\n return function() {\n return x;\n };\n}\n","import sparse from \"./sparse.js\";\nimport {Selection} from \"./index.js\";\n\nexport default function() {\n return new Selection(this._exit || this._groups.map(sparse), this._parents);\n}\n","export default function(onenter, onupdate, onexit) {\n var enter = this.enter(), update = this, exit = this.exit();\n if (typeof onenter === \"function\") {\n enter = onenter(enter);\n if (enter) enter = enter.selection();\n } else {\n enter = enter.append(onenter + \"\");\n }\n if (onupdate != null) {\n update = onupdate(update);\n if (update) update = update.selection();\n }\n if (onexit == null) exit.remove(); else onexit(exit);\n return enter && update ? enter.merge(update).order() : update;\n}\n","import {Selection} from \"./index.js\";\n\nexport default function(context) {\n var selection = context.selection ? context.selection() : context;\n\n for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {\n for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {\n if (node = group0[i] || group1[i]) {\n merge[i] = node;\n }\n }\n }\n\n for (; j < m0; ++j) {\n merges[j] = groups0[j];\n }\n\n return new Selection(merges, this._parents);\n}\n","export default function() {\n\n for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {\n for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {\n if (node = group[i]) {\n if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);\n next = node;\n }\n }\n }\n\n return this;\n}\n","export default function() {\n var callback = arguments[0];\n arguments[0] = this;\n callback.apply(null, arguments);\n return this;\n}\n","export default function() {\n return Array.from(this);\n}\n","export default function() {\n\n for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {\n for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {\n var node = group[i];\n if (node) return node;\n }\n }\n\n return null;\n}\n","export default function() {\n let size = 0;\n for (const node of this) ++size; // eslint-disable-line no-unused-vars\n return size;\n}\n","export default function() {\n return !this.node();\n}\n","export default function(callback) {\n\n for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {\n for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {\n if (node = group[i]) callback.call(node, node.__data__, i, group);\n }\n }\n\n return this;\n}\n","import creator from \"../creator.js\";\n\nexport default function(name) {\n var create = typeof name === \"function\" ? name : creator(name);\n return this.select(function() {\n return this.appendChild(create.apply(this, arguments));\n });\n}\n","export default function(value) {\n return arguments.length\n ? this.property(\"__data__\", value)\n : this.node().__data__;\n}\n","export default function*() {\n for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {\n for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {\n if (node = group[i]) yield node;\n }\n }\n}\n","export default x => () => x;\n","import constant from \"./constant.js\";\n\nfunction linear(a, d) {\n return function(t) {\n return a + t * d;\n };\n}\n\nfunction exponential(a, b, y) {\n return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {\n return Math.pow(a + t * b, y);\n };\n}\n\nexport function hue(a, b) {\n var d = b - a;\n return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant(isNaN(a) ? b : a);\n}\n\nexport function gamma(y) {\n return (y = +y) === 1 ? nogamma : function(a, b) {\n return b - a ? exponential(a, b, y) : constant(isNaN(a) ? b : a);\n };\n}\n\nexport default function nogamma(a, b) {\n var d = b - a;\n return d ? linear(a, d) : constant(isNaN(a) ? b : a);\n}\n","import {rgb as colorRgb} from \"d3-color\";\nimport basis from \"./basis.js\";\nimport basisClosed from \"./basisClosed.js\";\nimport nogamma, {gamma} from \"./color.js\";\n\nexport default (function rgbGamma(y) {\n var color = gamma(y);\n\n function rgb(start, end) {\n var r = color((start = colorRgb(start)).r, (end = colorRgb(end)).r),\n g = color(start.g, end.g),\n b = color(start.b, end.b),\n opacity = nogamma(start.opacity, end.opacity);\n return function(t) {\n start.r = r(t);\n start.g = g(t);\n start.b = b(t);\n start.opacity = opacity(t);\n return start + \"\";\n };\n }\n\n rgb.gamma = rgbGamma;\n\n return rgb;\n})(1);\n\nfunction rgbSpline(spline) {\n return function(colors) {\n var n = colors.length,\n r = new Array(n),\n g = new Array(n),\n b = new Array(n),\n i, color;\n for (i = 0; i < n; ++i) {\n color = colorRgb(colors[i]);\n r[i] = color.r || 0;\n g[i] = color.g || 0;\n b[i] = color.b || 0;\n }\n r = spline(r);\n g = spline(g);\n b = spline(b);\n color.opacity = 1;\n return function(t) {\n color.r = r(t);\n color.g = g(t);\n color.b = b(t);\n return color + \"\";\n };\n };\n}\n\nexport var rgbBasis = rgbSpline(basis);\nexport var rgbBasisClosed = rgbSpline(basisClosed);\n","export default function(a, b) {\n if (!b) b = [];\n var n = a ? Math.min(b.length, a.length) : 0,\n c = b.slice(),\n i;\n return function(t) {\n for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;\n return c;\n };\n}\n\nexport function isNumberArray(x) {\n return ArrayBuffer.isView(x) && !(x instanceof DataView);\n}\n","import value from \"./value.js\";\nimport numberArray, {isNumberArray} from \"./numberArray.js\";\n\nexport default function(a, b) {\n return (isNumberArray(b) ? numberArray : genericArray)(a, b);\n}\n\nexport function genericArray(a, b) {\n var nb = b ? b.length : 0,\n na = a ? Math.min(nb, a.length) : 0,\n x = new Array(na),\n c = new Array(nb),\n i;\n\n for (i = 0; i < na; ++i) x[i] = value(a[i], b[i]);\n for (; i < nb; ++i) c[i] = b[i];\n\n return function(t) {\n for (i = 0; i < na; ++i) c[i] = x[i](t);\n return c;\n };\n}\n","export default function(a, b) {\n var d = new Date;\n return a = +a, b = +b, function(t) {\n return d.setTime(a * (1 - t) + b * t), d;\n };\n}\n","export default function(a, b) {\n return a = +a, b = +b, function(t) {\n return a * (1 - t) + b * t;\n };\n}\n","import value from \"./value.js\";\n\nexport default function(a, b) {\n var i = {},\n c = {},\n k;\n\n if (a === null || typeof a !== \"object\") a = {};\n if (b === null || typeof b !== \"object\") b = {};\n\n for (k in b) {\n if (k in a) {\n i[k] = value(a[k], b[k]);\n } else {\n c[k] = b[k];\n }\n }\n\n return function(t) {\n for (k in i) c[k] = i[k](t);\n return c;\n };\n}\n","import number from \"./number.js\";\n\nvar reA = /[-+]?(?:\\d+\\.?\\d*|\\.?\\d+)(?:[eE][-+]?\\d+)?/g,\n reB = new RegExp(reA.source, \"g\");\n\nfunction zero(b) {\n return function() {\n return b;\n };\n}\n\nfunction one(b) {\n return function(t) {\n return b(t) + \"\";\n };\n}\n\nexport default function(a, b) {\n var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b\n am, // current match in a\n bm, // current match in b\n bs, // string preceding current number in b, if any\n i = -1, // index in s\n s = [], // string constants and placeholders\n q = []; // number interpolators\n\n // Coerce inputs to strings.\n a = a + \"\", b = b + \"\";\n\n // Interpolate pairs of numbers in a & b.\n while ((am = reA.exec(a))\n && (bm = reB.exec(b))) {\n if ((bs = bm.index) > bi) { // a string precedes the next number in b\n bs = b.slice(bi, bs);\n if (s[i]) s[i] += bs; // coalesce with previous string\n else s[++i] = bs;\n }\n if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match\n if (s[i]) s[i] += bm; // coalesce with previous string\n else s[++i] = bm;\n } else { // interpolate non-matching numbers\n s[++i] = null;\n q.push({i: i, x: number(am, bm)});\n }\n bi = reB.lastIndex;\n }\n\n // Add remains of b.\n if (bi < b.length) {\n bs = b.slice(bi);\n if (s[i]) s[i] += bs; // coalesce with previous string\n else s[++i] = bs;\n }\n\n // Special optimization for only a single match.\n // Otherwise, interpolate each of the numbers and rejoin the string.\n return s.length < 2 ? (q[0]\n ? one(q[0].x)\n : zero(b))\n : (b = q.length, function(t) {\n for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);\n return s.join(\"\");\n });\n}\n","import {color} from \"d3-color\";\nimport rgb from \"./rgb.js\";\nimport {genericArray} from \"./array.js\";\nimport date from \"./date.js\";\nimport number from \"./number.js\";\nimport object from \"./object.js\";\nimport string from \"./string.js\";\nimport constant from \"./constant.js\";\nimport numberArray, {isNumberArray} from \"./numberArray.js\";\n\nexport default function(a, b) {\n var t = typeof b, c;\n return b == null || t === \"boolean\" ? constant(b)\n : (t === \"number\" ? number\n : t === \"string\" ? ((c = color(b)) ? (b = c, rgb) : string)\n : b instanceof color ? rgb\n : b instanceof Date ? date\n : isNumberArray(b) ? numberArray\n : Array.isArray(b) ? genericArray\n : typeof b.valueOf !== \"function\" && typeof b.toString !== \"function\" || isNaN(b) ? object\n : number)(a, b);\n}\n","export default function(a, b) {\n return a = +a, b = +b, function(t) {\n return Math.round(a * (1 - t) + b * t);\n };\n}\n","var degrees = 180 / Math.PI;\n\nexport var identity = {\n translateX: 0,\n translateY: 0,\n rotate: 0,\n skewX: 0,\n scaleX: 1,\n scaleY: 1\n};\n\nexport default function(a, b, c, d, e, f) {\n var scaleX, scaleY, skewX;\n if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;\n if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;\n if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;\n if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;\n return {\n translateX: e,\n translateY: f,\n rotate: Math.atan2(b, a) * degrees,\n skewX: Math.atan(skewX) * degrees,\n scaleX: scaleX,\n scaleY: scaleY\n };\n}\n","import decompose, {identity} from \"./decompose.js\";\n\nvar svgNode;\n\n/* eslint-disable no-undef */\nexport function parseCss(value) {\n const m = new (typeof DOMMatrix === \"function\" ? DOMMatrix : WebKitCSSMatrix)(value + \"\");\n return m.isIdentity ? identity : decompose(m.a, m.b, m.c, m.d, m.e, m.f);\n}\n\nexport function parseSvg(value) {\n if (value == null) return identity;\n if (!svgNode) svgNode = document.createElementNS(\"http://www.w3.org/2000/svg\", \"g\");\n svgNode.setAttribute(\"transform\", value);\n if (!(value = svgNode.transform.baseVal.consolidate())) return identity;\n value = value.matrix;\n return decompose(value.a, value.b, value.c, value.d, value.e, value.f);\n}\n","import number from \"../number.js\";\nimport {parseCss, parseSvg} from \"./parse.js\";\n\nfunction interpolateTransform(parse, pxComma, pxParen, degParen) {\n\n function pop(s) {\n return s.length ? s.pop() + \" \" : \"\";\n }\n\n function translate(xa, ya, xb, yb, s, q) {\n if (xa !== xb || ya !== yb) {\n var i = s.push(\"translate(\", null, pxComma, null, pxParen);\n q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});\n } else if (xb || yb) {\n s.push(\"translate(\" + xb + pxComma + yb + pxParen);\n }\n }\n\n function rotate(a, b, s, q) {\n if (a !== b) {\n if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path\n q.push({i: s.push(pop(s) + \"rotate(\", null, degParen) - 2, x: number(a, b)});\n } else if (b) {\n s.push(pop(s) + \"rotate(\" + b + degParen);\n }\n }\n\n function skewX(a, b, s, q) {\n if (a !== b) {\n q.push({i: s.push(pop(s) + \"skewX(\", null, degParen) - 2, x: number(a, b)});\n } else if (b) {\n s.push(pop(s) + \"skewX(\" + b + degParen);\n }\n }\n\n function scale(xa, ya, xb, yb, s, q) {\n if (xa !== xb || ya !== yb) {\n var i = s.push(pop(s) + \"scale(\", null, \",\", null, \")\");\n q.push({i: i - 4, x: number(xa, xb)}, {i: i - 2, x: number(ya, yb)});\n } else if (xb !== 1 || yb !== 1) {\n s.push(pop(s) + \"scale(\" + xb + \",\" + yb + \")\");\n }\n }\n\n return function(a, b) {\n var s = [], // string constants and placeholders\n q = []; // number interpolators\n a = parse(a), b = parse(b);\n translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);\n rotate(a.rotate, b.rotate, s, q);\n skewX(a.skewX, b.skewX, s, q);\n scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);\n a = b = null; // gc\n return function(t) {\n var i = -1, n = q.length, o;\n while (++i < n) s[(o = q[i]).i] = o.x(t);\n return s.join(\"\");\n };\n };\n}\n\nexport var interpolateTransformCss = interpolateTransform(parseCss, \"px, \", \"px)\", \"deg)\");\nexport var interpolateTransformSvg = interpolateTransform(parseSvg, \", \", \")\", \")\");\n","var frame = 0, // is an animation frame pending?\n timeout = 0, // is a timeout pending?\n interval = 0, // are any timers active?\n pokeDelay = 1000, // how frequently we check for clock skew\n taskHead,\n taskTail,\n clockLast = 0,\n clockNow = 0,\n clockSkew = 0,\n clock = typeof performance === \"object\" && performance.now ? performance : Date,\n setFrame = typeof window === \"object\" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); };\n\nexport function now() {\n return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);\n}\n\nfunction clearNow() {\n clockNow = 0;\n}\n\nexport function Timer() {\n this._call =\n this._time =\n this._next = null;\n}\n\nTimer.prototype = timer.prototype = {\n constructor: Timer,\n restart: function(callback, delay, time) {\n if (typeof callback !== \"function\") throw new TypeError(\"callback is not a function\");\n time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);\n if (!this._next && taskTail !== this) {\n if (taskTail) taskTail._next = this;\n else taskHead = this;\n taskTail = this;\n }\n this._call = callback;\n this._time = time;\n sleep();\n },\n stop: function() {\n if (this._call) {\n this._call = null;\n this._time = Infinity;\n sleep();\n }\n }\n};\n\nexport function timer(callback, delay, time) {\n var t = new Timer;\n t.restart(callback, delay, time);\n return t;\n}\n\nexport function timerFlush() {\n now(); // Get the current time, if not already set.\n ++frame; // Pretend we’ve set an alarm, if we haven’t already.\n var t = taskHead, e;\n while (t) {\n if ((e = clockNow - t._time) >= 0) t._call.call(undefined, e);\n t = t._next;\n }\n --frame;\n}\n\nfunction wake() {\n clockNow = (clockLast = clock.now()) + clockSkew;\n frame = timeout = 0;\n try {\n timerFlush();\n } finally {\n frame = 0;\n nap();\n clockNow = 0;\n }\n}\n\nfunction poke() {\n var now = clock.now(), delay = now - clockLast;\n if (delay > pokeDelay) clockSkew -= delay, clockLast = now;\n}\n\nfunction nap() {\n var t0, t1 = taskHead, t2, time = Infinity;\n while (t1) {\n if (t1._call) {\n if (time > t1._time) time = t1._time;\n t0 = t1, t1 = t1._next;\n } else {\n t2 = t1._next, t1._next = null;\n t1 = t0 ? t0._next = t2 : taskHead = t2;\n }\n }\n taskTail = t0;\n sleep(time);\n}\n\nfunction sleep(time) {\n if (frame) return; // Soonest alarm already set, or will be.\n if (timeout) timeout = clearTimeout(timeout);\n var delay = time - clockNow; // Strictly less than if we recomputed clockNow.\n if (delay > 24) {\n if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);\n if (interval) interval = clearInterval(interval);\n } else {\n if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);\n frame = 1, setFrame(wake);\n }\n}\n","import {Timer} from \"./timer.js\";\n\nexport default function(callback, delay, time) {\n var t = new Timer;\n delay = delay == null ? 0 : +delay;\n t.restart(elapsed => {\n t.stop();\n callback(elapsed + delay);\n }, delay, time);\n return t;\n}\n","import {dispatch} from \"d3-dispatch\";\nimport {timer, timeout} from \"d3-timer\";\n\nvar emptyOn = dispatch(\"start\", \"end\", \"cancel\", \"interrupt\");\nvar emptyTween = [];\n\nexport var CREATED = 0;\nexport var SCHEDULED = 1;\nexport var STARTING = 2;\nexport var STARTED = 3;\nexport var RUNNING = 4;\nexport var ENDING = 5;\nexport var ENDED = 6;\n\nexport default function(node, name, id, index, group, timing) {\n var schedules = node.__transition;\n if (!schedules) node.__transition = {};\n else if (id in schedules) return;\n create(node, id, {\n name: name,\n index: index, // For context during callback.\n group: group, // For context during callback.\n on: emptyOn,\n tween: emptyTween,\n time: timing.time,\n delay: timing.delay,\n duration: timing.duration,\n ease: timing.ease,\n timer: null,\n state: CREATED\n });\n}\n\nexport function init(node, id) {\n var schedule = get(node, id);\n if (schedule.state > CREATED) throw new Error(\"too late; already scheduled\");\n return schedule;\n}\n\nexport function set(node, id) {\n var schedule = get(node, id);\n if (schedule.state > STARTED) throw new Error(\"too late; already running\");\n return schedule;\n}\n\nexport function get(node, id) {\n var schedule = node.__transition;\n if (!schedule || !(schedule = schedule[id])) throw new Error(\"transition not found\");\n return schedule;\n}\n\nfunction create(node, id, self) {\n var schedules = node.__transition,\n tween;\n\n // Initialize the self timer when the transition is created.\n // Note the actual delay is not known until the first callback!\n schedules[id] = self;\n self.timer = timer(schedule, 0, self.time);\n\n function schedule(elapsed) {\n self.state = SCHEDULED;\n self.timer.restart(start, self.delay, self.time);\n\n // If the elapsed delay is less than our first sleep, start immediately.\n if (self.delay <= elapsed) start(elapsed - self.delay);\n }\n\n function start(elapsed) {\n var i, j, n, o;\n\n // If the state is not SCHEDULED, then we previously errored on start.\n if (self.state !== SCHEDULED) return stop();\n\n for (i in schedules) {\n o = schedules[i];\n if (o.name !== self.name) continue;\n\n // While this element already has a starting transition during this frame,\n // defer starting an interrupting transition until that transition has a\n // chance to tick (and possibly end); see d3/d3-transition#54!\n if (o.state === STARTED) return timeout(start);\n\n // Interrupt the active transition, if any.\n if (o.state === RUNNING) {\n o.state = ENDED;\n o.timer.stop();\n o.on.call(\"interrupt\", node, node.__data__, o.index, o.group);\n delete schedules[i];\n }\n\n // Cancel any pre-empted transitions.\n else if (+i < id) {\n o.state = ENDED;\n o.timer.stop();\n o.on.call(\"cancel\", node, node.__data__, o.index, o.group);\n delete schedules[i];\n }\n }\n\n // Defer the first tick to end of the current frame; see d3/d3#1576.\n // Note the transition may be canceled after start and before the first tick!\n // Note this must be scheduled before the start event; see d3/d3-transition#16!\n // Assuming this is successful, subsequent callbacks go straight to tick.\n timeout(function() {\n if (self.state === STARTED) {\n self.state = RUNNING;\n self.timer.restart(tick, self.delay, self.time);\n tick(elapsed);\n }\n });\n\n // Dispatch the start event.\n // Note this must be done before the tween are initialized.\n self.state = STARTING;\n self.on.call(\"start\", node, node.__data__, self.index, self.group);\n if (self.state !== STARTING) return; // interrupted\n self.state = STARTED;\n\n // Initialize the tween, deleting null tween.\n tween = new Array(n = self.tween.length);\n for (i = 0, j = -1; i < n; ++i) {\n if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {\n tween[++j] = o;\n }\n }\n tween.length = j + 1;\n }\n\n function tick(elapsed) {\n var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),\n i = -1,\n n = tween.length;\n\n while (++i < n) {\n tween[i].call(node, t);\n }\n\n // Dispatch the end event.\n if (self.state === ENDING) {\n self.on.call(\"end\", node, node.__data__, self.index, self.group);\n stop();\n }\n }\n\n function stop() {\n self.state = ENDED;\n self.timer.stop();\n delete schedules[id];\n for (var i in schedules) return; // eslint-disable-line no-unused-vars\n delete node.__transition;\n }\n}\n","import {get, set} from \"./schedule.js\";\n\nfunction tweenRemove(id, name) {\n var tween0, tween1;\n return function() {\n var schedule = set(this, id),\n tween = schedule.tween;\n\n // If this node shared tween with the previous node,\n // just assign the updated shared tween and we’re done!\n // Otherwise, copy-on-write.\n if (tween !== tween0) {\n tween1 = tween0 = tween;\n for (var i = 0, n = tween1.length; i < n; ++i) {\n if (tween1[i].name === name) {\n tween1 = tween1.slice();\n tween1.splice(i, 1);\n break;\n }\n }\n }\n\n schedule.tween = tween1;\n };\n}\n\nfunction tweenFunction(id, name, value) {\n var tween0, tween1;\n if (typeof value !== \"function\") throw new Error;\n return function() {\n var schedule = set(this, id),\n tween = schedule.tween;\n\n // If this node shared tween with the previous node,\n // just assign the updated shared tween and we’re done!\n // Otherwise, copy-on-write.\n if (tween !== tween0) {\n tween1 = (tween0 = tween).slice();\n for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {\n if (tween1[i].name === name) {\n tween1[i] = t;\n break;\n }\n }\n if (i === n) tween1.push(t);\n }\n\n schedule.tween = tween1;\n };\n}\n\nexport default function(name, value) {\n var id = this._id;\n\n name += \"\";\n\n if (arguments.length < 2) {\n var tween = get(this.node(), id).tween;\n for (var i = 0, n = tween.length, t; i < n; ++i) {\n if ((t = tween[i]).name === name) {\n return t.value;\n }\n }\n return null;\n }\n\n return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));\n}\n\nexport function tweenValue(transition, name, value) {\n var id = transition._id;\n\n transition.each(function() {\n var schedule = set(this, id);\n (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);\n });\n\n return function(node) {\n return get(node, id).value[name];\n };\n}\n","import {color} from \"d3-color\";\nimport {interpolateNumber, interpolateRgb, interpolateString} from \"d3-interpolate\";\n\nexport default function(a, b) {\n var c;\n return (typeof b === \"number\" ? interpolateNumber\n : b instanceof color ? interpolateRgb\n : (c = color(b)) ? (b = c, interpolateRgb)\n : interpolateString)(a, b);\n}\n","import {interpolateTransformSvg as interpolateTransform} from \"d3-interpolate\";\nimport {namespace} from \"d3-selection\";\nimport {tweenValue} from \"./tween.js\";\nimport interpolate from \"./interpolate.js\";\n\nfunction attrRemove(name) {\n return function() {\n this.removeAttribute(name);\n };\n}\n\nfunction attrRemoveNS(fullname) {\n return function() {\n this.removeAttributeNS(fullname.space, fullname.local);\n };\n}\n\nfunction attrConstant(name, interpolate, value1) {\n var string00,\n string1 = value1 + \"\",\n interpolate0;\n return function() {\n var string0 = this.getAttribute(name);\n return string0 === string1 ? null\n : string0 === string00 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, value1);\n };\n}\n\nfunction attrConstantNS(fullname, interpolate, value1) {\n var string00,\n string1 = value1 + \"\",\n interpolate0;\n return function() {\n var string0 = this.getAttributeNS(fullname.space, fullname.local);\n return string0 === string1 ? null\n : string0 === string00 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, value1);\n };\n}\n\nfunction attrFunction(name, interpolate, value) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0, value1 = value(this), string1;\n if (value1 == null) return void this.removeAttribute(name);\n string0 = this.getAttribute(name);\n string1 = value1 + \"\";\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n };\n}\n\nfunction attrFunctionNS(fullname, interpolate, value) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0, value1 = value(this), string1;\n if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);\n string0 = this.getAttributeNS(fullname.space, fullname.local);\n string1 = value1 + \"\";\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n };\n}\n\nexport default function(name, value) {\n var fullname = namespace(name), i = fullname === \"transform\" ? interpolateTransform : interpolate;\n return this.attrTween(name, typeof value === \"function\"\n ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, \"attr.\" + name, value))\n : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname)\n : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));\n}\n","import {namespace} from \"d3-selection\";\n\nfunction attrInterpolate(name, i) {\n return function(t) {\n this.setAttribute(name, i.call(this, t));\n };\n}\n\nfunction attrInterpolateNS(fullname, i) {\n return function(t) {\n this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));\n };\n}\n\nfunction attrTweenNS(fullname, value) {\n var t0, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);\n return t0;\n }\n tween._value = value;\n return tween;\n}\n\nfunction attrTween(name, value) {\n var t0, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);\n return t0;\n }\n tween._value = value;\n return tween;\n}\n\nexport default function(name, value) {\n var key = \"attr.\" + name;\n if (arguments.length < 2) return (key = this.tween(key)) && key._value;\n if (value == null) return this.tween(key, null);\n if (typeof value !== \"function\") throw new Error;\n var fullname = namespace(name);\n return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));\n}\n","import {get, init} from \"./schedule.js\";\n\nfunction delayFunction(id, value) {\n return function() {\n init(this, id).delay = +value.apply(this, arguments);\n };\n}\n\nfunction delayConstant(id, value) {\n return value = +value, function() {\n init(this, id).delay = value;\n };\n}\n\nexport default function(value) {\n var id = this._id;\n\n return arguments.length\n ? this.each((typeof value === \"function\"\n ? delayFunction\n : delayConstant)(id, value))\n : get(this.node(), id).delay;\n}\n","import {get, set} from \"./schedule.js\";\n\nfunction durationFunction(id, value) {\n return function() {\n set(this, id).duration = +value.apply(this, arguments);\n };\n}\n\nfunction durationConstant(id, value) {\n return value = +value, function() {\n set(this, id).duration = value;\n };\n}\n\nexport default function(value) {\n var id = this._id;\n\n return arguments.length\n ? this.each((typeof value === \"function\"\n ? durationFunction\n : durationConstant)(id, value))\n : get(this.node(), id).duration;\n}\n","import {selection} from \"d3-selection\";\n\nvar Selection = selection.prototype.constructor;\n\nexport default function() {\n return new Selection(this._groups, this._parents);\n}\n","import {interpolateTransformCss as interpolateTransform} from \"d3-interpolate\";\nimport {style} from \"d3-selection\";\nimport {set} from \"./schedule.js\";\nimport {tweenValue} from \"./tween.js\";\nimport interpolate from \"./interpolate.js\";\n\nfunction styleNull(name, interpolate) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0 = style(this, name),\n string1 = (this.style.removeProperty(name), style(this, name));\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, string10 = string1);\n };\n}\n\nfunction styleRemove(name) {\n return function() {\n this.style.removeProperty(name);\n };\n}\n\nfunction styleConstant(name, interpolate, value1) {\n var string00,\n string1 = value1 + \"\",\n interpolate0;\n return function() {\n var string0 = style(this, name);\n return string0 === string1 ? null\n : string0 === string00 ? interpolate0\n : interpolate0 = interpolate(string00 = string0, value1);\n };\n}\n\nfunction styleFunction(name, interpolate, value) {\n var string00,\n string10,\n interpolate0;\n return function() {\n var string0 = style(this, name),\n value1 = value(this),\n string1 = value1 + \"\";\n if (value1 == null) string1 = value1 = (this.style.removeProperty(name), style(this, name));\n return string0 === string1 ? null\n : string0 === string00 && string1 === string10 ? interpolate0\n : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));\n };\n}\n\nfunction styleMaybeRemove(id, name) {\n var on0, on1, listener0, key = \"style.\" + name, event = \"end.\" + key, remove;\n return function() {\n var schedule = set(this, id),\n on = schedule.on,\n listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined;\n\n // If this node shared a dispatch with the previous node,\n // just assign the updated shared dispatch and we’re done!\n // Otherwise, copy-on-write.\n if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);\n\n schedule.on = on1;\n };\n}\n\nexport default function(name, value, priority) {\n var i = (name += \"\") === \"transform\" ? interpolateTransform : interpolate;\n return value == null ? this\n .styleTween(name, styleNull(name, i))\n .on(\"end.style.\" + name, styleRemove(name))\n : typeof value === \"function\" ? this\n .styleTween(name, styleFunction(name, i, tweenValue(this, \"style.\" + name, value)))\n .each(styleMaybeRemove(this._id, name))\n : this\n .styleTween(name, styleConstant(name, i, value), priority)\n .on(\"end.style.\" + name, null);\n}\n","import {selection} from \"d3-selection\";\nimport transition_attr from \"./attr.js\";\nimport transition_attrTween from \"./attrTween.js\";\nimport transition_delay from \"./delay.js\";\nimport transition_duration from \"./duration.js\";\nimport transition_ease from \"./ease.js\";\nimport transition_easeVarying from \"./easeVarying.js\";\nimport transition_filter from \"./filter.js\";\nimport transition_merge from \"./merge.js\";\nimport transition_on from \"./on.js\";\nimport transition_remove from \"./remove.js\";\nimport transition_select from \"./select.js\";\nimport transition_selectAll from \"./selectAll.js\";\nimport transition_selection from \"./selection.js\";\nimport transition_style from \"./style.js\";\nimport transition_styleTween from \"./styleTween.js\";\nimport transition_text from \"./text.js\";\nimport transition_textTween from \"./textTween.js\";\nimport transition_transition from \"./transition.js\";\nimport transition_tween from \"./tween.js\";\nimport transition_end from \"./end.js\";\n\nvar id = 0;\n\nexport function Transition(groups, parents, name, id) {\n this._groups = groups;\n this._parents = parents;\n this._name = name;\n this._id = id;\n}\n\nexport default function transition(name) {\n return selection().transition(name);\n}\n\nexport function newId() {\n return ++id;\n}\n\nvar selection_prototype = selection.prototype;\n\nTransition.prototype = transition.prototype = {\n constructor: Transition,\n select: transition_select,\n selectAll: transition_selectAll,\n selectChild: selection_prototype.selectChild,\n selectChildren: selection_prototype.selectChildren,\n filter: transition_filter,\n merge: transition_merge,\n selection: transition_selection,\n transition: transition_transition,\n call: selection_prototype.call,\n nodes: selection_prototype.nodes,\n node: selection_prototype.node,\n size: selection_prototype.size,\n empty: selection_prototype.empty,\n each: selection_prototype.each,\n on: transition_on,\n attr: transition_attr,\n attrTween: transition_attrTween,\n style: transition_style,\n styleTween: transition_styleTween,\n text: transition_text,\n textTween: transition_textTween,\n remove: transition_remove,\n tween: transition_tween,\n delay: transition_delay,\n duration: transition_duration,\n ease: transition_ease,\n easeVarying: transition_easeVarying,\n end: transition_end,\n [Symbol.iterator]: selection_prototype[Symbol.iterator]\n};\n","import {selector} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function(select) {\n var name = this._name,\n id = this._id;\n\n if (typeof select !== \"function\") select = selector(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {\n if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {\n if (\"__data__\" in node) subnode.__data__ = node.__data__;\n subgroup[i] = subnode;\n schedule(subgroup[i], name, id, i, subgroup, get(node, id));\n }\n }\n }\n\n return new Transition(subgroups, this._parents, name, id);\n}\n","import {selectorAll} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function(select) {\n var name = this._name,\n id = this._id;\n\n if (typeof select !== \"function\") select = selectorAll(select);\n\n for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) {\n if (child = children[k]) {\n schedule(child, name, id, k, children, inherit);\n }\n }\n subgroups.push(children);\n parents.push(node);\n }\n }\n }\n\n return new Transition(subgroups, parents, name, id);\n}\n","import {matcher} from \"d3-selection\";\nimport {Transition} from \"./index.js\";\n\nexport default function(match) {\n if (typeof match !== \"function\") match = matcher(match);\n\n for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {\n if ((node = group[i]) && match.call(node, node.__data__, i, group)) {\n subgroup.push(node);\n }\n }\n }\n\n return new Transition(subgroups, this._parents, this._name, this._id);\n}\n","import {Transition} from \"./index.js\";\n\nexport default function(transition) {\n if (transition._id !== this._id) throw new Error;\n\n for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {\n for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {\n if (node = group0[i] || group1[i]) {\n merge[i] = node;\n }\n }\n }\n\n for (; j < m0; ++j) {\n merges[j] = groups0[j];\n }\n\n return new Transition(merges, this._parents, this._name, this._id);\n}\n","import {Transition, newId} from \"./index.js\";\nimport schedule, {get} from \"./schedule.js\";\n\nexport default function() {\n var name = this._name,\n id0 = this._id,\n id1 = newId();\n\n for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n var inherit = get(node, id0);\n schedule(node, name, id1, i, group, {\n time: inherit.time + inherit.delay + inherit.duration,\n delay: 0,\n duration: inherit.duration,\n ease: inherit.ease\n });\n }\n }\n }\n\n return new Transition(groups, this._parents, name, id1);\n}\n","import {get, set, init} from \"./schedule.js\";\n\nfunction start(name) {\n return (name + \"\").trim().split(/^|\\s+/).every(function(t) {\n var i = t.indexOf(\".\");\n if (i >= 0) t = t.slice(0, i);\n return !t || t === \"start\";\n });\n}\n\nfunction onFunction(id, name, listener) {\n var on0, on1, sit = start(name) ? init : set;\n return function() {\n var schedule = sit(this, id),\n on = schedule.on;\n\n // If this node shared a dispatch with the previous node,\n // just assign the updated shared dispatch and we’re done!\n // Otherwise, copy-on-write.\n if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);\n\n schedule.on = on1;\n };\n}\n\nexport default function(name, listener) {\n var id = this._id;\n\n return arguments.length < 2\n ? get(this.node(), id).on.on(name)\n : this.each(onFunction(id, name, listener));\n}\n","function styleInterpolate(name, i, priority) {\n return function(t) {\n this.style.setProperty(name, i.call(this, t), priority);\n };\n}\n\nfunction styleTween(name, value, priority) {\n var t, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);\n return t;\n }\n tween._value = value;\n return tween;\n}\n\nexport default function(name, value, priority) {\n var key = \"style.\" + (name += \"\");\n if (arguments.length < 2) return (key = this.tween(key)) && key._value;\n if (value == null) return this.tween(key, null);\n if (typeof value !== \"function\") throw new Error;\n return this.tween(key, styleTween(name, value, priority == null ? \"\" : priority));\n}\n","import {tweenValue} from \"./tween.js\";\n\nfunction textConstant(value) {\n return function() {\n this.textContent = value;\n };\n}\n\nfunction textFunction(value) {\n return function() {\n var value1 = value(this);\n this.textContent = value1 == null ? \"\" : value1;\n };\n}\n\nexport default function(value) {\n return this.tween(\"text\", typeof value === \"function\"\n ? textFunction(tweenValue(this, \"text\", value))\n : textConstant(value == null ? \"\" : value + \"\"));\n}\n","function textInterpolate(i) {\n return function(t) {\n this.textContent = i.call(this, t);\n };\n}\n\nfunction textTween(value) {\n var t0, i0;\n function tween() {\n var i = value.apply(this, arguments);\n if (i !== i0) t0 = (i0 = i) && textInterpolate(i);\n return t0;\n }\n tween._value = value;\n return tween;\n}\n\nexport default function(value) {\n var key = \"text\";\n if (arguments.length < 1) return (key = this.tween(key)) && key._value;\n if (value == null) return this.tween(key, null);\n if (typeof value !== \"function\") throw new Error;\n return this.tween(key, textTween(value));\n}\n","function removeFunction(id) {\n return function() {\n var parent = this.parentNode;\n for (var i in this.__transition) if (+i !== id) return;\n if (parent) parent.removeChild(this);\n };\n}\n\nexport default function() {\n return this.on(\"end.remove\", removeFunction(this._id));\n}\n","import {get, set} from \"./schedule.js\";\n\nfunction easeConstant(id, value) {\n if (typeof value !== \"function\") throw new Error;\n return function() {\n set(this, id).ease = value;\n };\n}\n\nexport default function(value) {\n var id = this._id;\n\n return arguments.length\n ? this.each(easeConstant(id, value))\n : get(this.node(), id).ease;\n}\n","import {set} from \"./schedule.js\";\n\nfunction easeVarying(id, value) {\n return function() {\n var v = value.apply(this, arguments);\n if (typeof v !== \"function\") throw new Error;\n set(this, id).ease = v;\n };\n}\n\nexport default function(value) {\n if (typeof value !== \"function\") throw new Error;\n return this.each(easeVarying(this._id, value));\n}\n","import {set} from \"./schedule.js\";\n\nexport default function() {\n var on0, on1, that = this, id = that._id, size = that.size();\n return new Promise(function(resolve, reject) {\n var cancel = {value: reject},\n end = {value: function() { if (--size === 0) resolve(); }};\n\n that.each(function() {\n var schedule = set(this, id),\n on = schedule.on;\n\n // If this node shared a dispatch with the previous node,\n // just assign the updated shared dispatch and we’re done!\n // Otherwise, copy-on-write.\n if (on !== on0) {\n on1 = (on0 = on).copy();\n on1._.cancel.push(cancel);\n on1._.interrupt.push(cancel);\n on1._.end.push(end);\n }\n\n schedule.on = on1;\n });\n\n // The selection was empty, resolve end immediately\n if (size === 0) resolve();\n });\n}\n","import {Transition, newId} from \"../transition/index.js\";\nimport schedule from \"../transition/schedule.js\";\nimport {easeCubicInOut} from \"d3-ease\";\nimport {now} from \"d3-timer\";\n\nvar defaultTiming = {\n time: null, // Set on use.\n delay: 0,\n duration: 250,\n ease: easeCubicInOut\n};\n\nfunction inherit(node, id) {\n var timing;\n while (!(timing = node.__transition) || !(timing = timing[id])) {\n if (!(node = node.parentNode)) {\n throw new Error(`transition ${id} not found`);\n }\n }\n return timing;\n}\n\nexport default function(name) {\n var id,\n timing;\n\n if (name instanceof Transition) {\n id = name._id, name = name._name;\n } else {\n id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + \"\";\n }\n\n for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {\n for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {\n if (node = group[i]) {\n schedule(node, name, id, i, group, timing || inherit(node, id));\n }\n }\n }\n\n return new Transition(groups, this._parents, name, id);\n}\n","export function cubicIn(t) {\n return t * t * t;\n}\n\nexport function cubicOut(t) {\n return --t * t * t + 1;\n}\n\nexport function cubicInOut(t) {\n return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;\n}\n","import {selection} from \"d3-selection\";\nimport selection_interrupt from \"./interrupt.js\";\nimport selection_transition from \"./transition.js\";\n\nselection.prototype.interrupt = selection_interrupt;\nselection.prototype.transition = selection_transition;\n","import interrupt from \"../interrupt.js\";\n\nexport default function(name) {\n return this.each(function() {\n interrupt(this, name);\n });\n}\n","import {STARTING, ENDING, ENDED} from \"./transition/schedule.js\";\n\nexport default function(node, name) {\n var schedules = node.__transition,\n schedule,\n active,\n empty = true,\n i;\n\n if (!schedules) return;\n\n name = name == null ? null : name + \"\";\n\n for (i in schedules) {\n if ((schedule = schedules[i]).name !== name) { empty = false; continue; }\n active = schedule.state > STARTING && schedule.state < ENDING;\n schedule.state = ENDED;\n schedule.timer.stop();\n schedule.on.call(active ? \"interrupt\" : \"cancel\", node, node.__data__, schedule.index, schedule.group);\n delete schedules[i];\n }\n\n if (empty) delete node.__transition;\n}\n","const pi = Math.PI,\n tau = 2 * pi,\n epsilon = 1e-6,\n tauEpsilon = tau - epsilon;\n\nfunction append(strings) {\n this._ += strings[0];\n for (let i = 1, n = strings.length; i < n; ++i) {\n this._ += arguments[i] + strings[i];\n }\n}\n\nfunction appendRound(digits) {\n let d = Math.floor(digits);\n if (!(d >= 0)) throw new Error(`invalid digits: ${digits}`);\n if (d > 15) return append;\n const k = 10 ** d;\n return function(strings) {\n this._ += strings[0];\n for (let i = 1, n = strings.length; i < n; ++i) {\n this._ += Math.round(arguments[i] * k) / k + strings[i];\n }\n };\n}\n\nexport class Path {\n constructor(digits) {\n this._x0 = this._y0 = // start of current subpath\n this._x1 = this._y1 = null; // end of current subpath\n this._ = \"\";\n this._append = digits == null ? append : appendRound(digits);\n }\n moveTo(x, y) {\n this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}`;\n }\n closePath() {\n if (this._x1 !== null) {\n this._x1 = this._x0, this._y1 = this._y0;\n this._append`Z`;\n }\n }\n lineTo(x, y) {\n this._append`L${this._x1 = +x},${this._y1 = +y}`;\n }\n quadraticCurveTo(x1, y1, x, y) {\n this._append`Q${+x1},${+y1},${this._x1 = +x},${this._y1 = +y}`;\n }\n bezierCurveTo(x1, y1, x2, y2, x, y) {\n this._append`C${+x1},${+y1},${+x2},${+y2},${this._x1 = +x},${this._y1 = +y}`;\n }\n arcTo(x1, y1, x2, y2, r) {\n x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(`negative radius: ${r}`);\n\n let x0 = this._x1,\n y0 = this._y1,\n x21 = x2 - x1,\n y21 = y2 - y1,\n x01 = x0 - x1,\n y01 = y0 - y1,\n l01_2 = x01 * x01 + y01 * y01;\n\n // Is this path empty? Move to (x1,y1).\n if (this._x1 === null) {\n this._append`M${this._x1 = x1},${this._y1 = y1}`;\n }\n\n // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.\n else if (!(l01_2 > epsilon));\n\n // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?\n // Equivalently, is (x1,y1) coincident with (x2,y2)?\n // Or, is the radius zero? Line to (x1,y1).\n else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {\n this._append`L${this._x1 = x1},${this._y1 = y1}`;\n }\n\n // Otherwise, draw an arc!\n else {\n let x20 = x2 - x0,\n y20 = y2 - y0,\n l21_2 = x21 * x21 + y21 * y21,\n l20_2 = x20 * x20 + y20 * y20,\n l21 = Math.sqrt(l21_2),\n l01 = Math.sqrt(l01_2),\n l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),\n t01 = l / l01,\n t21 = l / l21;\n\n // If the start tangent is not coincident with (x0,y0), line to.\n if (Math.abs(t01 - 1) > epsilon) {\n this._append`L${x1 + t01 * x01},${y1 + t01 * y01}`;\n }\n\n this._append`A${r},${r},0,0,${+(y01 * x20 > x01 * y20)},${this._x1 = x1 + t21 * x21},${this._y1 = y1 + t21 * y21}`;\n }\n }\n arc(x, y, r, a0, a1, ccw) {\n x = +x, y = +y, r = +r, ccw = !!ccw;\n\n // Is the radius negative? Error.\n if (r < 0) throw new Error(`negative radius: ${r}`);\n\n let dx = r * Math.cos(a0),\n dy = r * Math.sin(a0),\n x0 = x + dx,\n y0 = y + dy,\n cw = 1 ^ ccw,\n da = ccw ? a0 - a1 : a1 - a0;\n\n // Is this path empty? Move to (x0,y0).\n if (this._x1 === null) {\n this._append`M${x0},${y0}`;\n }\n\n // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).\n else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {\n this._append`L${x0},${y0}`;\n }\n\n // Is this arc empty? We’re done.\n if (!r) return;\n\n // Does the angle go the wrong way? Flip the direction.\n if (da < 0) da = da % tau + tau;\n\n // Is this a complete circle? Draw two arcs to complete the circle.\n if (da > tauEpsilon) {\n this._append`A${r},${r},0,1,${cw},${x - dx},${y - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;\n }\n\n // Is this arc non-empty? Draw an arc!\n else if (da > epsilon) {\n this._append`A${r},${r},0,${+(da >= pi)},${cw},${this._x1 = x + r * Math.cos(a1)},${this._y1 = y + r * Math.sin(a1)}`;\n }\n }\n rect(x, y, w, h) {\n this._append`M${this._x0 = this._x1 = +x},${this._y0 = this._y1 = +y}h${w = +w}v${+h}h${-w}Z`;\n }\n toString() {\n return this._;\n }\n}\n\nexport function path() {\n return new Path;\n}\n\n// Allow instanceof d3.path\npath.prototype = Path.prototype;\n\nexport function pathRound(digits = 3) {\n return new Path(+digits);\n}\n","export default function(x) {\n return Math.abs(x = Math.round(x)) >= 1e21\n ? x.toLocaleString(\"en\").replace(/,/g, \"\")\n : x.toString(10);\n}\n\n// Computes the decimal coefficient and exponent of the specified number x with\n// significant digits p, where x is positive and p is in [1, 21] or undefined.\n// For example, formatDecimalParts(1.23) returns [\"123\", 0].\nexport function formatDecimalParts(x, p) {\n if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf(\"e\")) < 0) return null; // NaN, Β±Infinity\n var i, coefficient = x.slice(0, i);\n\n // The string returned by toExponential either has the form \\d\\.\\d+e[-+]\\d+\n // (e.g., 1.2e+3) or the form \\de[-+]\\d+ (e.g., 1e+3).\n return [\n coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,\n +x.slice(i + 1)\n ];\n}\n","import {formatDecimalParts} from \"./formatDecimal.js\";\n\nexport default function(x) {\n return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;\n}\n","// [[fill]align][sign][symbol][0][width][,][.precision][~][type]\nvar re = /^(?:(.)?([<>=^]))?([+\\-( ])?([$#])?(0)?(\\d+)?(,)?(\\.\\d+)?(~)?([a-z%])?$/i;\n\nexport default function formatSpecifier(specifier) {\n if (!(match = re.exec(specifier))) throw new Error(\"invalid format: \" + specifier);\n var match;\n return new FormatSpecifier({\n fill: match[1],\n align: match[2],\n sign: match[3],\n symbol: match[4],\n zero: match[5],\n width: match[6],\n comma: match[7],\n precision: match[8] && match[8].slice(1),\n trim: match[9],\n type: match[10]\n });\n}\n\nformatSpecifier.prototype = FormatSpecifier.prototype; // instanceof\n\nexport function FormatSpecifier(specifier) {\n this.fill = specifier.fill === undefined ? \" \" : specifier.fill + \"\";\n this.align = specifier.align === undefined ? \">\" : specifier.align + \"\";\n this.sign = specifier.sign === undefined ? \"-\" : specifier.sign + \"\";\n this.symbol = specifier.symbol === undefined ? \"\" : specifier.symbol + \"\";\n this.zero = !!specifier.zero;\n this.width = specifier.width === undefined ? undefined : +specifier.width;\n this.comma = !!specifier.comma;\n this.precision = specifier.precision === undefined ? undefined : +specifier.precision;\n this.trim = !!specifier.trim;\n this.type = specifier.type === undefined ? \"\" : specifier.type + \"\";\n}\n\nFormatSpecifier.prototype.toString = function() {\n return this.fill\n + this.align\n + this.sign\n + this.symbol\n + (this.zero ? \"0\" : \"\")\n + (this.width === undefined ? \"\" : Math.max(1, this.width | 0))\n + (this.comma ? \",\" : \"\")\n + (this.precision === undefined ? \"\" : \".\" + Math.max(0, this.precision | 0))\n + (this.trim ? \"~\" : \"\")\n + this.type;\n};\n","import {formatDecimalParts} from \"./formatDecimal.js\";\n\nexport var prefixExponent;\n\nexport default function(x, p) {\n var d = formatDecimalParts(x, p);\n if (!d) return x + \"\";\n var coefficient = d[0],\n exponent = d[1],\n i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,\n n = coefficient.length;\n return i === n ? coefficient\n : i > n ? coefficient + new Array(i - n + 1).join(\"0\")\n : i > 0 ? coefficient.slice(0, i) + \".\" + coefficient.slice(i)\n : \"0.\" + new Array(1 - i).join(\"0\") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!\n}\n","import {formatDecimalParts} from \"./formatDecimal.js\";\n\nexport default function(x, p) {\n var d = formatDecimalParts(x, p);\n if (!d) return x + \"\";\n var coefficient = d[0],\n exponent = d[1];\n return exponent < 0 ? \"0.\" + new Array(-exponent).join(\"0\") + coefficient\n : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + \".\" + coefficient.slice(exponent + 1)\n : coefficient + new Array(exponent - coefficient.length + 2).join(\"0\");\n}\n","import formatDecimal from \"./formatDecimal.js\";\nimport formatPrefixAuto from \"./formatPrefixAuto.js\";\nimport formatRounded from \"./formatRounded.js\";\n\nexport default {\n \"%\": (x, p) => (x * 100).toFixed(p),\n \"b\": (x) => Math.round(x).toString(2),\n \"c\": (x) => x + \"\",\n \"d\": formatDecimal,\n \"e\": (x, p) => x.toExponential(p),\n \"f\": (x, p) => x.toFixed(p),\n \"g\": (x, p) => x.toPrecision(p),\n \"o\": (x) => Math.round(x).toString(8),\n \"p\": (x, p) => formatRounded(x * 100, p),\n \"r\": formatRounded,\n \"s\": formatPrefixAuto,\n \"X\": (x) => Math.round(x).toString(16).toUpperCase(),\n \"x\": (x) => Math.round(x).toString(16)\n};\n","export default function(x) {\n return x;\n}\n","import exponent from \"./exponent.js\";\nimport formatGroup from \"./formatGroup.js\";\nimport formatNumerals from \"./formatNumerals.js\";\nimport formatSpecifier from \"./formatSpecifier.js\";\nimport formatTrim from \"./formatTrim.js\";\nimport formatTypes from \"./formatTypes.js\";\nimport {prefixExponent} from \"./formatPrefixAuto.js\";\nimport identity from \"./identity.js\";\n\nvar map = Array.prototype.map,\n prefixes = [\"y\",\"z\",\"a\",\"f\",\"p\",\"n\",\"Β΅\",\"m\",\"\",\"k\",\"M\",\"G\",\"T\",\"P\",\"E\",\"Z\",\"Y\"];\n\nexport default function(locale) {\n var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map.call(locale.grouping, Number), locale.thousands + \"\"),\n currencyPrefix = locale.currency === undefined ? \"\" : locale.currency[0] + \"\",\n currencySuffix = locale.currency === undefined ? \"\" : locale.currency[1] + \"\",\n decimal = locale.decimal === undefined ? \".\" : locale.decimal + \"\",\n numerals = locale.numerals === undefined ? identity : formatNumerals(map.call(locale.numerals, String)),\n percent = locale.percent === undefined ? \"%\" : locale.percent + \"\",\n minus = locale.minus === undefined ? \"βˆ’\" : locale.minus + \"\",\n nan = locale.nan === undefined ? \"NaN\" : locale.nan + \"\";\n\n function newFormat(specifier) {\n specifier = formatSpecifier(specifier);\n\n var fill = specifier.fill,\n align = specifier.align,\n sign = specifier.sign,\n symbol = specifier.symbol,\n zero = specifier.zero,\n width = specifier.width,\n comma = specifier.comma,\n precision = specifier.precision,\n trim = specifier.trim,\n type = specifier.type;\n\n // The \"n\" type is an alias for \",g\".\n if (type === \"n\") comma = true, type = \"g\";\n\n // The \"\" type, and any invalid type, is an alias for \".12~g\".\n else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = \"g\";\n\n // If zero fill is specified, padding goes after sign and before digits.\n if (zero || (fill === \"0\" && align === \"=\")) zero = true, fill = \"0\", align = \"=\";\n\n // Compute the prefix and suffix.\n // For SI-prefix, the suffix is lazily computed.\n var prefix = symbol === \"$\" ? currencyPrefix : symbol === \"#\" && /[boxX]/.test(type) ? \"0\" + type.toLowerCase() : \"\",\n suffix = symbol === \"$\" ? currencySuffix : /[%p]/.test(type) ? percent : \"\";\n\n // What format function should we use?\n // Is this an integer type?\n // Can this type generate exponential notation?\n var formatType = formatTypes[type],\n maybeSuffix = /[defgprs%]/.test(type);\n\n // Set the default precision if not specified,\n // or clamp the specified precision to the supported range.\n // For significant precision, it must be in [1, 21].\n // For fixed precision, it must be in [0, 20].\n precision = precision === undefined ? 6\n : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))\n : Math.max(0, Math.min(20, precision));\n\n function format(value) {\n var valuePrefix = prefix,\n valueSuffix = suffix,\n i, n, c;\n\n if (type === \"c\") {\n valueSuffix = formatType(value) + valueSuffix;\n value = \"\";\n } else {\n value = +value;\n\n // Determine the sign. -0 is not less than 0, but 1 / -0 is!\n var valueNegative = value < 0 || 1 / value < 0;\n\n // Perform the initial formatting.\n value = isNaN(value) ? nan : formatType(Math.abs(value), precision);\n\n // Trim insignificant zeros.\n if (trim) value = formatTrim(value);\n\n // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.\n if (valueNegative && +value === 0 && sign !== \"+\") valueNegative = false;\n\n // Compute the prefix and suffix.\n valuePrefix = (valueNegative ? (sign === \"(\" ? sign : minus) : sign === \"-\" || sign === \"(\" ? \"\" : sign) + valuePrefix;\n valueSuffix = (type === \"s\" ? prefixes[8 + prefixExponent / 3] : \"\") + valueSuffix + (valueNegative && sign === \"(\" ? \")\" : \"\");\n\n // Break the formatted value into the integer β€œvalue” part that can be\n // grouped, and fractional or exponential β€œsuffix” part that is not.\n if (maybeSuffix) {\n i = -1, n = value.length;\n while (++i < n) {\n if (c = value.charCodeAt(i), 48 > c || c > 57) {\n valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;\n value = value.slice(0, i);\n break;\n }\n }\n }\n }\n\n // If the fill character is not \"0\", grouping is applied before padding.\n if (comma && !zero) value = group(value, Infinity);\n\n // Compute the padding.\n var length = valuePrefix.length + value.length + valueSuffix.length,\n padding = length < width ? new Array(width - length + 1).join(fill) : \"\";\n\n // If the fill character is \"0\", grouping is applied after padding.\n if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = \"\";\n\n // Reconstruct the final output based on the desired alignment.\n switch (align) {\n case \"<\": value = valuePrefix + value + valueSuffix + padding; break;\n case \"=\": value = valuePrefix + padding + value + valueSuffix; break;\n case \"^\": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;\n default: value = padding + valuePrefix + value + valueSuffix; break;\n }\n\n return numerals(value);\n }\n\n format.toString = function() {\n return specifier + \"\";\n };\n\n return format;\n }\n\n function formatPrefix(specifier, value) {\n var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = \"f\", specifier)),\n e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,\n k = Math.pow(10, -e),\n prefix = prefixes[8 + e / 3];\n return function(value) {\n return f(k * value) + prefix;\n };\n }\n\n return {\n format: newFormat,\n formatPrefix: formatPrefix\n };\n}\n","import formatLocale from \"./locale.js\";\n\nvar locale;\nexport var format;\nexport var formatPrefix;\n\ndefaultLocale({\n thousands: \",\",\n grouping: [3],\n currency: [\"$\", \"\"]\n});\n\nexport default function defaultLocale(definition) {\n locale = formatLocale(definition);\n format = locale.format;\n formatPrefix = locale.formatPrefix;\n return locale;\n}\n","export default function(grouping, thousands) {\n return function(value, width) {\n var i = value.length,\n t = [],\n j = 0,\n g = grouping[0],\n length = 0;\n\n while (i > 0 && g > 0) {\n if (length + g + 1 > width) g = Math.max(1, width - length);\n t.push(value.substring(i -= g, i + g));\n if ((length += g + 1) > width) break;\n g = grouping[j = (j + 1) % grouping.length];\n }\n\n return t.reverse().join(thousands);\n };\n}\n","export default function(numerals) {\n return function(value) {\n return value.replace(/[0-9]/g, function(i) {\n return numerals[+i];\n });\n };\n}\n","// Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.\nexport default function(s) {\n out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {\n switch (s[i]) {\n case \".\": i0 = i1 = i; break;\n case \"0\": if (i0 === 0) i0 = i; i1 = i; break;\n default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break;\n }\n }\n return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;\n}\n","export function initRange(domain, range) {\n switch (arguments.length) {\n case 0: break;\n case 1: this.range(domain); break;\n default: this.range(range).domain(domain); break;\n }\n return this;\n}\n\nexport function initInterpolator(domain, interpolator) {\n switch (arguments.length) {\n case 0: break;\n case 1: {\n if (typeof domain === \"function\") this.interpolator(domain);\n else this.range(domain);\n break;\n }\n default: {\n this.domain(domain);\n if (typeof interpolator === \"function\") this.interpolator(interpolator);\n else this.range(interpolator);\n break;\n }\n }\n return this;\n}\n","export default function number(x) {\n return +x;\n}\n","import {bisect} from \"d3-array\";\nimport {interpolate as interpolateValue, interpolateNumber, interpolateRound} from \"d3-interpolate\";\nimport constant from \"./constant.js\";\nimport number from \"./number.js\";\n\nvar unit = [0, 1];\n\nexport function identity(x) {\n return x;\n}\n\nfunction normalize(a, b) {\n return (b -= (a = +a))\n ? function(x) { return (x - a) / b; }\n : constant(isNaN(b) ? NaN : 0.5);\n}\n\nfunction clamper(a, b) {\n var t;\n if (a > b) t = a, a = b, b = t;\n return function(x) { return Math.max(a, Math.min(b, x)); };\n}\n\n// normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].\n// interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].\nfunction bimap(domain, range, interpolate) {\n var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];\n if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);\n else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);\n return function(x) { return r0(d0(x)); };\n}\n\nfunction polymap(domain, range, interpolate) {\n var j = Math.min(domain.length, range.length) - 1,\n d = new Array(j),\n r = new Array(j),\n i = -1;\n\n // Reverse descending domains.\n if (domain[j] < domain[0]) {\n domain = domain.slice().reverse();\n range = range.slice().reverse();\n }\n\n while (++i < j) {\n d[i] = normalize(domain[i], domain[i + 1]);\n r[i] = interpolate(range[i], range[i + 1]);\n }\n\n return function(x) {\n var i = bisect(domain, x, 1, j) - 1;\n return r[i](d[i](x));\n };\n}\n\nexport function copy(source, target) {\n return target\n .domain(source.domain())\n .range(source.range())\n .interpolate(source.interpolate())\n .clamp(source.clamp())\n .unknown(source.unknown());\n}\n\nexport function transformer() {\n var domain = unit,\n range = unit,\n interpolate = interpolateValue,\n transform,\n untransform,\n unknown,\n clamp = identity,\n piecewise,\n output,\n input;\n\n function rescale() {\n var n = Math.min(domain.length, range.length);\n if (clamp !== identity) clamp = clamper(domain[0], domain[n - 1]);\n piecewise = n > 2 ? polymap : bimap;\n output = input = null;\n return scale;\n }\n\n function scale(x) {\n return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));\n }\n\n scale.invert = function(y) {\n return clamp(untransform((input || (input = piecewise(range, domain.map(transform), interpolateNumber)))(y)));\n };\n\n scale.domain = function(_) {\n return arguments.length ? (domain = Array.from(_, number), rescale()) : domain.slice();\n };\n\n scale.range = function(_) {\n return arguments.length ? (range = Array.from(_), rescale()) : range.slice();\n };\n\n scale.rangeRound = function(_) {\n return range = Array.from(_), interpolate = interpolateRound, rescale();\n };\n\n scale.clamp = function(_) {\n return arguments.length ? (clamp = _ ? true : identity, rescale()) : clamp !== identity;\n };\n\n scale.interpolate = function(_) {\n return arguments.length ? (interpolate = _, rescale()) : interpolate;\n };\n\n scale.unknown = function(_) {\n return arguments.length ? (unknown = _, scale) : unknown;\n };\n\n return function(t, u) {\n transform = t, untransform = u;\n return rescale();\n };\n}\n\nexport default function continuous() {\n return transformer()(identity, identity);\n}\n","export default function constants(x) {\n return function() {\n return x;\n };\n}\n","import {tickStep} from \"d3-array\";\nimport {format, formatPrefix, formatSpecifier, precisionFixed, precisionPrefix, precisionRound} from \"d3-format\";\n\nexport default function tickFormat(start, stop, count, specifier) {\n var step = tickStep(start, stop, count),\n precision;\n specifier = formatSpecifier(specifier == null ? \",f\" : specifier);\n switch (specifier.type) {\n case \"s\": {\n var value = Math.max(Math.abs(start), Math.abs(stop));\n if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;\n return formatPrefix(specifier, value);\n }\n case \"\":\n case \"e\":\n case \"g\":\n case \"p\":\n case \"r\": {\n if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === \"e\");\n break;\n }\n case \"f\":\n case \"%\": {\n if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === \"%\") * 2;\n break;\n }\n }\n return format(specifier);\n}\n","import exponent from \"./exponent.js\";\n\nexport default function(step, value) {\n return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));\n}\n","import exponent from \"./exponent.js\";\n\nexport default function(step, max) {\n step = Math.abs(step), max = Math.abs(max) - step;\n return Math.max(0, exponent(max) - exponent(step)) + 1;\n}\n","import exponent from \"./exponent.js\";\n\nexport default function(step) {\n return Math.max(0, -exponent(Math.abs(step)));\n}\n","import {ticks, tickIncrement} from \"d3-array\";\nimport continuous, {copy} from \"./continuous.js\";\nimport {initRange} from \"./init.js\";\nimport tickFormat from \"./tickFormat.js\";\n\nexport function linearish(scale) {\n var domain = scale.domain;\n\n scale.ticks = function(count) {\n var d = domain();\n return ticks(d[0], d[d.length - 1], count == null ? 10 : count);\n };\n\n scale.tickFormat = function(count, specifier) {\n var d = domain();\n return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);\n };\n\n scale.nice = function(count) {\n if (count == null) count = 10;\n\n var d = domain();\n var i0 = 0;\n var i1 = d.length - 1;\n var start = d[i0];\n var stop = d[i1];\n var prestep;\n var step;\n var maxIter = 10;\n\n if (stop < start) {\n step = start, start = stop, stop = step;\n step = i0, i0 = i1, i1 = step;\n }\n \n while (maxIter-- > 0) {\n step = tickIncrement(start, stop, count);\n if (step === prestep) {\n d[i0] = start\n d[i1] = stop\n return domain(d);\n } else if (step > 0) {\n start = Math.floor(start / step) * step;\n stop = Math.ceil(stop / step) * step;\n } else if (step < 0) {\n start = Math.ceil(start * step) / step;\n stop = Math.floor(stop * step) / step;\n } else {\n break;\n }\n prestep = step;\n }\n\n return scale;\n };\n\n return scale;\n}\n\nexport default function linear() {\n var scale = continuous();\n\n scale.copy = function() {\n return copy(scale, linear());\n };\n\n initRange.apply(scale, arguments);\n\n return linearish(scale);\n}\n","const t0 = new Date, t1 = new Date;\n\nexport function timeInterval(floori, offseti, count, field) {\n\n function interval(date) {\n return floori(date = arguments.length === 0 ? new Date : new Date(+date)), date;\n }\n\n interval.floor = (date) => {\n return floori(date = new Date(+date)), date;\n };\n\n interval.ceil = (date) => {\n return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;\n };\n\n interval.round = (date) => {\n const d0 = interval(date), d1 = interval.ceil(date);\n return date - d0 < d1 - date ? d0 : d1;\n };\n\n interval.offset = (date, step) => {\n return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;\n };\n\n interval.range = (start, stop, step) => {\n const range = [];\n start = interval.ceil(start);\n step = step == null ? 1 : Math.floor(step);\n if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date\n let previous;\n do range.push(previous = new Date(+start)), offseti(start, step), floori(start);\n while (previous < start && start < stop);\n return range;\n };\n\n interval.filter = (test) => {\n return timeInterval((date) => {\n if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);\n }, (date, step) => {\n if (date >= date) {\n if (step < 0) while (++step <= 0) {\n while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty\n } else while (--step >= 0) {\n while (offseti(date, +1), !test(date)) {} // eslint-disable-line no-empty\n }\n }\n });\n };\n\n if (count) {\n interval.count = (start, end) => {\n t0.setTime(+start), t1.setTime(+end);\n floori(t0), floori(t1);\n return Math.floor(count(t0, t1));\n };\n\n interval.every = (step) => {\n step = Math.floor(step);\n return !isFinite(step) || !(step > 0) ? null\n : !(step > 1) ? interval\n : interval.filter(field\n ? (d) => field(d) % step === 0\n : (d) => interval.count(0, d) % step === 0);\n };\n }\n\n return interval;\n}\n","import {timeInterval} from \"./interval.js\";\n\nexport const millisecond = timeInterval(() => {\n // noop\n}, (date, step) => {\n date.setTime(+date + step);\n}, (start, end) => {\n return end - start;\n});\n\n// An optimized implementation for this simple case.\nmillisecond.every = (k) => {\n k = Math.floor(k);\n if (!isFinite(k) || !(k > 0)) return null;\n if (!(k > 1)) return millisecond;\n return timeInterval((date) => {\n date.setTime(Math.floor(date / k) * k);\n }, (date, step) => {\n date.setTime(+date + step * k);\n }, (start, end) => {\n return (end - start) / k;\n });\n};\n\nexport const milliseconds = millisecond.range;\n","export const durationSecond = 1000;\nexport const durationMinute = durationSecond * 60;\nexport const durationHour = durationMinute * 60;\nexport const durationDay = durationHour * 24;\nexport const durationWeek = durationDay * 7;\nexport const durationMonth = durationDay * 30;\nexport const durationYear = durationDay * 365;\n","import {timeInterval} from \"./interval.js\";\nimport {durationSecond} from \"./duration.js\";\n\nexport const second = timeInterval((date) => {\n date.setTime(date - date.getMilliseconds());\n}, (date, step) => {\n date.setTime(+date + step * durationSecond);\n}, (start, end) => {\n return (end - start) / durationSecond;\n}, (date) => {\n return date.getUTCSeconds();\n});\n\nexport const seconds = second.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationMinute, durationSecond} from \"./duration.js\";\n\nexport const timeMinute = timeInterval((date) => {\n date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond);\n}, (date, step) => {\n date.setTime(+date + step * durationMinute);\n}, (start, end) => {\n return (end - start) / durationMinute;\n}, (date) => {\n return date.getMinutes();\n});\n\nexport const timeMinutes = timeMinute.range;\n\nexport const utcMinute = timeInterval((date) => {\n date.setUTCSeconds(0, 0);\n}, (date, step) => {\n date.setTime(+date + step * durationMinute);\n}, (start, end) => {\n return (end - start) / durationMinute;\n}, (date) => {\n return date.getUTCMinutes();\n});\n\nexport const utcMinutes = utcMinute.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationHour, durationMinute, durationSecond} from \"./duration.js\";\n\nexport const timeHour = timeInterval((date) => {\n date.setTime(date - date.getMilliseconds() - date.getSeconds() * durationSecond - date.getMinutes() * durationMinute);\n}, (date, step) => {\n date.setTime(+date + step * durationHour);\n}, (start, end) => {\n return (end - start) / durationHour;\n}, (date) => {\n return date.getHours();\n});\n\nexport const timeHours = timeHour.range;\n\nexport const utcHour = timeInterval((date) => {\n date.setUTCMinutes(0, 0, 0);\n}, (date, step) => {\n date.setTime(+date + step * durationHour);\n}, (start, end) => {\n return (end - start) / durationHour;\n}, (date) => {\n return date.getUTCHours();\n});\n\nexport const utcHours = utcHour.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationDay, durationMinute} from \"./duration.js\";\n\nexport const timeDay = timeInterval(\n date => date.setHours(0, 0, 0, 0),\n (date, step) => date.setDate(date.getDate() + step),\n (start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay,\n date => date.getDate() - 1\n);\n\nexport const timeDays = timeDay.range;\n\nexport const utcDay = timeInterval((date) => {\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCDate(date.getUTCDate() + step);\n}, (start, end) => {\n return (end - start) / durationDay;\n}, (date) => {\n return date.getUTCDate() - 1;\n});\n\nexport const utcDays = utcDay.range;\n\nexport const unixDay = timeInterval((date) => {\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCDate(date.getUTCDate() + step);\n}, (start, end) => {\n return (end - start) / durationDay;\n}, (date) => {\n return Math.floor(date / durationDay);\n});\n\nexport const unixDays = unixDay.range;\n","import {timeInterval} from \"./interval.js\";\nimport {durationMinute, durationWeek} from \"./duration.js\";\n\nfunction timeWeekday(i) {\n return timeInterval((date) => {\n date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);\n date.setHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setDate(date.getDate() + step * 7);\n }, (start, end) => {\n return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;\n });\n}\n\nexport const timeSunday = timeWeekday(0);\nexport const timeMonday = timeWeekday(1);\nexport const timeTuesday = timeWeekday(2);\nexport const timeWednesday = timeWeekday(3);\nexport const timeThursday = timeWeekday(4);\nexport const timeFriday = timeWeekday(5);\nexport const timeSaturday = timeWeekday(6);\n\nexport const timeSundays = timeSunday.range;\nexport const timeMondays = timeMonday.range;\nexport const timeTuesdays = timeTuesday.range;\nexport const timeWednesdays = timeWednesday.range;\nexport const timeThursdays = timeThursday.range;\nexport const timeFridays = timeFriday.range;\nexport const timeSaturdays = timeSaturday.range;\n\nfunction utcWeekday(i) {\n return timeInterval((date) => {\n date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);\n date.setUTCHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setUTCDate(date.getUTCDate() + step * 7);\n }, (start, end) => {\n return (end - start) / durationWeek;\n });\n}\n\nexport const utcSunday = utcWeekday(0);\nexport const utcMonday = utcWeekday(1);\nexport const utcTuesday = utcWeekday(2);\nexport const utcWednesday = utcWeekday(3);\nexport const utcThursday = utcWeekday(4);\nexport const utcFriday = utcWeekday(5);\nexport const utcSaturday = utcWeekday(6);\n\nexport const utcSundays = utcSunday.range;\nexport const utcMondays = utcMonday.range;\nexport const utcTuesdays = utcTuesday.range;\nexport const utcWednesdays = utcWednesday.range;\nexport const utcThursdays = utcThursday.range;\nexport const utcFridays = utcFriday.range;\nexport const utcSaturdays = utcSaturday.range;\n","import {timeInterval} from \"./interval.js\";\n\nexport const timeMonth = timeInterval((date) => {\n date.setDate(1);\n date.setHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setMonth(date.getMonth() + step);\n}, (start, end) => {\n return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;\n}, (date) => {\n return date.getMonth();\n});\n\nexport const timeMonths = timeMonth.range;\n\nexport const utcMonth = timeInterval((date) => {\n date.setUTCDate(1);\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCMonth(date.getUTCMonth() + step);\n}, (start, end) => {\n return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;\n}, (date) => {\n return date.getUTCMonth();\n});\n\nexport const utcMonths = utcMonth.range;\n","import {timeInterval} from \"./interval.js\";\n\nexport const timeYear = timeInterval((date) => {\n date.setMonth(0, 1);\n date.setHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setFullYear(date.getFullYear() + step);\n}, (start, end) => {\n return end.getFullYear() - start.getFullYear();\n}, (date) => {\n return date.getFullYear();\n});\n\n// An optimized implementation for this simple case.\ntimeYear.every = (k) => {\n return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {\n date.setFullYear(Math.floor(date.getFullYear() / k) * k);\n date.setMonth(0, 1);\n date.setHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setFullYear(date.getFullYear() + step * k);\n });\n};\n\nexport const timeYears = timeYear.range;\n\nexport const utcYear = timeInterval((date) => {\n date.setUTCMonth(0, 1);\n date.setUTCHours(0, 0, 0, 0);\n}, (date, step) => {\n date.setUTCFullYear(date.getUTCFullYear() + step);\n}, (start, end) => {\n return end.getUTCFullYear() - start.getUTCFullYear();\n}, (date) => {\n return date.getUTCFullYear();\n});\n\n// An optimized implementation for this simple case.\nutcYear.every = (k) => {\n return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {\n date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);\n date.setUTCMonth(0, 1);\n date.setUTCHours(0, 0, 0, 0);\n }, (date, step) => {\n date.setUTCFullYear(date.getUTCFullYear() + step * k);\n });\n};\n\nexport const utcYears = utcYear.range;\n","import {bisector, tickStep} from \"d3-array\";\nimport {durationDay, durationHour, durationMinute, durationMonth, durationSecond, durationWeek, durationYear} from \"./duration.js\";\nimport {millisecond} from \"./millisecond.js\";\nimport {second} from \"./second.js\";\nimport {timeMinute, utcMinute} from \"./minute.js\";\nimport {timeHour, utcHour} from \"./hour.js\";\nimport {timeDay, unixDay} from \"./day.js\";\nimport {timeSunday, utcSunday} from \"./week.js\";\nimport {timeMonth, utcMonth} from \"./month.js\";\nimport {timeYear, utcYear} from \"./year.js\";\n\nfunction ticker(year, month, week, day, hour, minute) {\n\n const tickIntervals = [\n [second, 1, durationSecond],\n [second, 5, 5 * durationSecond],\n [second, 15, 15 * durationSecond],\n [second, 30, 30 * durationSecond],\n [minute, 1, durationMinute],\n [minute, 5, 5 * durationMinute],\n [minute, 15, 15 * durationMinute],\n [minute, 30, 30 * durationMinute],\n [ hour, 1, durationHour ],\n [ hour, 3, 3 * durationHour ],\n [ hour, 6, 6 * durationHour ],\n [ hour, 12, 12 * durationHour ],\n [ day, 1, durationDay ],\n [ day, 2, 2 * durationDay ],\n [ week, 1, durationWeek ],\n [ month, 1, durationMonth ],\n [ month, 3, 3 * durationMonth ],\n [ year, 1, durationYear ]\n ];\n\n function ticks(start, stop, count) {\n const reverse = stop < start;\n if (reverse) [start, stop] = [stop, start];\n const interval = count && typeof count.range === \"function\" ? count : tickInterval(start, stop, count);\n const ticks = interval ? interval.range(start, +stop + 1) : []; // inclusive stop\n return reverse ? ticks.reverse() : ticks;\n }\n\n function tickInterval(start, stop, count) {\n const target = Math.abs(stop - start) / count;\n const i = bisector(([,, step]) => step).right(tickIntervals, target);\n if (i === tickIntervals.length) return year.every(tickStep(start / durationYear, stop / durationYear, count));\n if (i === 0) return millisecond.every(Math.max(tickStep(start, stop, count), 1));\n const [t, step] = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];\n return t.every(step);\n }\n\n return [ticks, tickInterval];\n}\n\nconst [utcTicks, utcTickInterval] = ticker(utcYear, utcMonth, utcSunday, unixDay, utcHour, utcMinute);\nconst [timeTicks, timeTickInterval] = ticker(timeYear, timeMonth, timeSunday, timeDay, timeHour, timeMinute);\n\nexport {utcTicks, utcTickInterval, timeTicks, timeTickInterval};\n","import {\n timeDay,\n timeSunday,\n timeMonday,\n timeThursday,\n timeYear,\n utcDay,\n utcSunday,\n utcMonday,\n utcThursday,\n utcYear\n} from \"d3-time\";\n\nfunction localDate(d) {\n if (0 <= d.y && d.y < 100) {\n var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);\n date.setFullYear(d.y);\n return date;\n }\n return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);\n}\n\nfunction utcDate(d) {\n if (0 <= d.y && d.y < 100) {\n var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));\n date.setUTCFullYear(d.y);\n return date;\n }\n return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));\n}\n\nfunction newDate(y, m, d) {\n return {y: y, m: m, d: d, H: 0, M: 0, S: 0, L: 0};\n}\n\nexport default function formatLocale(locale) {\n var locale_dateTime = locale.dateTime,\n locale_date = locale.date,\n locale_time = locale.time,\n locale_periods = locale.periods,\n locale_weekdays = locale.days,\n locale_shortWeekdays = locale.shortDays,\n locale_months = locale.months,\n locale_shortMonths = locale.shortMonths;\n\n var periodRe = formatRe(locale_periods),\n periodLookup = formatLookup(locale_periods),\n weekdayRe = formatRe(locale_weekdays),\n weekdayLookup = formatLookup(locale_weekdays),\n shortWeekdayRe = formatRe(locale_shortWeekdays),\n shortWeekdayLookup = formatLookup(locale_shortWeekdays),\n monthRe = formatRe(locale_months),\n monthLookup = formatLookup(locale_months),\n shortMonthRe = formatRe(locale_shortMonths),\n shortMonthLookup = formatLookup(locale_shortMonths);\n\n var formats = {\n \"a\": formatShortWeekday,\n \"A\": formatWeekday,\n \"b\": formatShortMonth,\n \"B\": formatMonth,\n \"c\": null,\n \"d\": formatDayOfMonth,\n \"e\": formatDayOfMonth,\n \"f\": formatMicroseconds,\n \"g\": formatYearISO,\n \"G\": formatFullYearISO,\n \"H\": formatHour24,\n \"I\": formatHour12,\n \"j\": formatDayOfYear,\n \"L\": formatMilliseconds,\n \"m\": formatMonthNumber,\n \"M\": formatMinutes,\n \"p\": formatPeriod,\n \"q\": formatQuarter,\n \"Q\": formatUnixTimestamp,\n \"s\": formatUnixTimestampSeconds,\n \"S\": formatSeconds,\n \"u\": formatWeekdayNumberMonday,\n \"U\": formatWeekNumberSunday,\n \"V\": formatWeekNumberISO,\n \"w\": formatWeekdayNumberSunday,\n \"W\": formatWeekNumberMonday,\n \"x\": null,\n \"X\": null,\n \"y\": formatYear,\n \"Y\": formatFullYear,\n \"Z\": formatZone,\n \"%\": formatLiteralPercent\n };\n\n var utcFormats = {\n \"a\": formatUTCShortWeekday,\n \"A\": formatUTCWeekday,\n \"b\": formatUTCShortMonth,\n \"B\": formatUTCMonth,\n \"c\": null,\n \"d\": formatUTCDayOfMonth,\n \"e\": formatUTCDayOfMonth,\n \"f\": formatUTCMicroseconds,\n \"g\": formatUTCYearISO,\n \"G\": formatUTCFullYearISO,\n \"H\": formatUTCHour24,\n \"I\": formatUTCHour12,\n \"j\": formatUTCDayOfYear,\n \"L\": formatUTCMilliseconds,\n \"m\": formatUTCMonthNumber,\n \"M\": formatUTCMinutes,\n \"p\": formatUTCPeriod,\n \"q\": formatUTCQuarter,\n \"Q\": formatUnixTimestamp,\n \"s\": formatUnixTimestampSeconds,\n \"S\": formatUTCSeconds,\n \"u\": formatUTCWeekdayNumberMonday,\n \"U\": formatUTCWeekNumberSunday,\n \"V\": formatUTCWeekNumberISO,\n \"w\": formatUTCWeekdayNumberSunday,\n \"W\": formatUTCWeekNumberMonday,\n \"x\": null,\n \"X\": null,\n \"y\": formatUTCYear,\n \"Y\": formatUTCFullYear,\n \"Z\": formatUTCZone,\n \"%\": formatLiteralPercent\n };\n\n var parses = {\n \"a\": parseShortWeekday,\n \"A\": parseWeekday,\n \"b\": parseShortMonth,\n \"B\": parseMonth,\n \"c\": parseLocaleDateTime,\n \"d\": parseDayOfMonth,\n \"e\": parseDayOfMonth,\n \"f\": parseMicroseconds,\n \"g\": parseYear,\n \"G\": parseFullYear,\n \"H\": parseHour24,\n \"I\": parseHour24,\n \"j\": parseDayOfYear,\n \"L\": parseMilliseconds,\n \"m\": parseMonthNumber,\n \"M\": parseMinutes,\n \"p\": parsePeriod,\n \"q\": parseQuarter,\n \"Q\": parseUnixTimestamp,\n \"s\": parseUnixTimestampSeconds,\n \"S\": parseSeconds,\n \"u\": parseWeekdayNumberMonday,\n \"U\": parseWeekNumberSunday,\n \"V\": parseWeekNumberISO,\n \"w\": parseWeekdayNumberSunday,\n \"W\": parseWeekNumberMonday,\n \"x\": parseLocaleDate,\n \"X\": parseLocaleTime,\n \"y\": parseYear,\n \"Y\": parseFullYear,\n \"Z\": parseZone,\n \"%\": parseLiteralPercent\n };\n\n // These recursive directive definitions must be deferred.\n formats.x = newFormat(locale_date, formats);\n formats.X = newFormat(locale_time, formats);\n formats.c = newFormat(locale_dateTime, formats);\n utcFormats.x = newFormat(locale_date, utcFormats);\n utcFormats.X = newFormat(locale_time, utcFormats);\n utcFormats.c = newFormat(locale_dateTime, utcFormats);\n\n function newFormat(specifier, formats) {\n return function(date) {\n var string = [],\n i = -1,\n j = 0,\n n = specifier.length,\n c,\n pad,\n format;\n\n if (!(date instanceof Date)) date = new Date(+date);\n\n while (++i < n) {\n if (specifier.charCodeAt(i) === 37) {\n string.push(specifier.slice(j, i));\n if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);\n else pad = c === \"e\" ? \" \" : \"0\";\n if (format = formats[c]) c = format(date, pad);\n string.push(c);\n j = i + 1;\n }\n }\n\n string.push(specifier.slice(j, i));\n return string.join(\"\");\n };\n }\n\n function newParse(specifier, Z) {\n return function(string) {\n var d = newDate(1900, undefined, 1),\n i = parseSpecifier(d, specifier, string += \"\", 0),\n week, day;\n if (i != string.length) return null;\n\n // If a UNIX timestamp is specified, return it.\n if (\"Q\" in d) return new Date(d.Q);\n if (\"s\" in d) return new Date(d.s * 1000 + (\"L\" in d ? d.L : 0));\n\n // If this is utcParse, never use the local timezone.\n if (Z && !(\"Z\" in d)) d.Z = 0;\n\n // The am-pm flag is 0 for AM, and 1 for PM.\n if (\"p\" in d) d.H = d.H % 12 + d.p * 12;\n\n // If the month was not specified, inherit from the quarter.\n if (d.m === undefined) d.m = \"q\" in d ? d.q : 0;\n\n // Convert day-of-week and week-of-year to day-of-year.\n if (\"V\" in d) {\n if (d.V < 1 || d.V > 53) return null;\n if (!(\"w\" in d)) d.w = 1;\n if (\"Z\" in d) {\n week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay();\n week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week);\n week = utcDay.offset(week, (d.V - 1) * 7);\n d.y = week.getUTCFullYear();\n d.m = week.getUTCMonth();\n d.d = week.getUTCDate() + (d.w + 6) % 7;\n } else {\n week = localDate(newDate(d.y, 0, 1)), day = week.getDay();\n week = day > 4 || day === 0 ? timeMonday.ceil(week) : timeMonday(week);\n week = timeDay.offset(week, (d.V - 1) * 7);\n d.y = week.getFullYear();\n d.m = week.getMonth();\n d.d = week.getDate() + (d.w + 6) % 7;\n }\n } else if (\"W\" in d || \"U\" in d) {\n if (!(\"w\" in d)) d.w = \"u\" in d ? d.u % 7 : \"W\" in d ? 1 : 0;\n day = \"Z\" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay();\n d.m = 0;\n d.d = \"W\" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;\n }\n\n // If a time zone is specified, all fields are interpreted as UTC and then\n // offset according to the specified time zone.\n if (\"Z\" in d) {\n d.H += d.Z / 100 | 0;\n d.M += d.Z % 100;\n return utcDate(d);\n }\n\n // Otherwise, all fields are in local time.\n return localDate(d);\n };\n }\n\n function parseSpecifier(d, specifier, string, j) {\n var i = 0,\n n = specifier.length,\n m = string.length,\n c,\n parse;\n\n while (i < n) {\n if (j >= m) return -1;\n c = specifier.charCodeAt(i++);\n if (c === 37) {\n c = specifier.charAt(i++);\n parse = parses[c in pads ? specifier.charAt(i++) : c];\n if (!parse || ((j = parse(d, string, j)) < 0)) return -1;\n } else if (c != string.charCodeAt(j++)) {\n return -1;\n }\n }\n\n return j;\n }\n\n function parsePeriod(d, string, i) {\n var n = periodRe.exec(string.slice(i));\n return n ? (d.p = periodLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseShortWeekday(d, string, i) {\n var n = shortWeekdayRe.exec(string.slice(i));\n return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseWeekday(d, string, i) {\n var n = weekdayRe.exec(string.slice(i));\n return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseShortMonth(d, string, i) {\n var n = shortMonthRe.exec(string.slice(i));\n return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseMonth(d, string, i) {\n var n = monthRe.exec(string.slice(i));\n return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;\n }\n\n function parseLocaleDateTime(d, string, i) {\n return parseSpecifier(d, locale_dateTime, string, i);\n }\n\n function parseLocaleDate(d, string, i) {\n return parseSpecifier(d, locale_date, string, i);\n }\n\n function parseLocaleTime(d, string, i) {\n return parseSpecifier(d, locale_time, string, i);\n }\n\n function formatShortWeekday(d) {\n return locale_shortWeekdays[d.getDay()];\n }\n\n function formatWeekday(d) {\n return locale_weekdays[d.getDay()];\n }\n\n function formatShortMonth(d) {\n return locale_shortMonths[d.getMonth()];\n }\n\n function formatMonth(d) {\n return locale_months[d.getMonth()];\n }\n\n function formatPeriod(d) {\n return locale_periods[+(d.getHours() >= 12)];\n }\n\n function formatQuarter(d) {\n return 1 + ~~(d.getMonth() / 3);\n }\n\n function formatUTCShortWeekday(d) {\n return locale_shortWeekdays[d.getUTCDay()];\n }\n\n function formatUTCWeekday(d) {\n return locale_weekdays[d.getUTCDay()];\n }\n\n function formatUTCShortMonth(d) {\n return locale_shortMonths[d.getUTCMonth()];\n }\n\n function formatUTCMonth(d) {\n return locale_months[d.getUTCMonth()];\n }\n\n function formatUTCPeriod(d) {\n return locale_periods[+(d.getUTCHours() >= 12)];\n }\n\n function formatUTCQuarter(d) {\n return 1 + ~~(d.getUTCMonth() / 3);\n }\n\n return {\n format: function(specifier) {\n var f = newFormat(specifier += \"\", formats);\n f.toString = function() { return specifier; };\n return f;\n },\n parse: function(specifier) {\n var p = newParse(specifier += \"\", false);\n p.toString = function() { return specifier; };\n return p;\n },\n utcFormat: function(specifier) {\n var f = newFormat(specifier += \"\", utcFormats);\n f.toString = function() { return specifier; };\n return f;\n },\n utcParse: function(specifier) {\n var p = newParse(specifier += \"\", true);\n p.toString = function() { return specifier; };\n return p;\n }\n };\n}\n\nvar pads = {\"-\": \"\", \"_\": \" \", \"0\": \"0\"},\n numberRe = /^\\s*\\d+/, // note: ignores next directive\n percentRe = /^%/,\n requoteRe = /[\\\\^$*+?|[\\]().{}]/g;\n\nfunction pad(value, fill, width) {\n var sign = value < 0 ? \"-\" : \"\",\n string = (sign ? -value : value) + \"\",\n length = string.length;\n return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);\n}\n\nfunction requote(s) {\n return s.replace(requoteRe, \"\\\\$&\");\n}\n\nfunction formatRe(names) {\n return new RegExp(\"^(?:\" + names.map(requote).join(\"|\") + \")\", \"i\");\n}\n\nfunction formatLookup(names) {\n return new Map(names.map((name, i) => [name.toLowerCase(), i]));\n}\n\nfunction parseWeekdayNumberSunday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.w = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekdayNumberMonday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.u = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberSunday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.U = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberISO(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.V = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseWeekNumberMonday(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.W = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseFullYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 4));\n return n ? (d.y = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;\n}\n\nfunction parseZone(d, string, i) {\n var n = /^(Z)|([+-]\\d\\d)(?::?(\\d\\d))?/.exec(string.slice(i, i + 6));\n return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || \"00\")), i + n[0].length) : -1;\n}\n\nfunction parseQuarter(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 1));\n return n ? (d.q = n[0] * 3 - 3, i + n[0].length) : -1;\n}\n\nfunction parseMonthNumber(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.m = n[0] - 1, i + n[0].length) : -1;\n}\n\nfunction parseDayOfMonth(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.d = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseDayOfYear(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 3));\n return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseHour24(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.H = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMinutes(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.M = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseSeconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 2));\n return n ? (d.S = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMilliseconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 3));\n return n ? (d.L = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseMicroseconds(d, string, i) {\n var n = numberRe.exec(string.slice(i, i + 6));\n return n ? (d.L = Math.floor(n[0] / 1000), i + n[0].length) : -1;\n}\n\nfunction parseLiteralPercent(d, string, i) {\n var n = percentRe.exec(string.slice(i, i + 1));\n return n ? i + n[0].length : -1;\n}\n\nfunction parseUnixTimestamp(d, string, i) {\n var n = numberRe.exec(string.slice(i));\n return n ? (d.Q = +n[0], i + n[0].length) : -1;\n}\n\nfunction parseUnixTimestampSeconds(d, string, i) {\n var n = numberRe.exec(string.slice(i));\n return n ? (d.s = +n[0], i + n[0].length) : -1;\n}\n\nfunction formatDayOfMonth(d, p) {\n return pad(d.getDate(), p, 2);\n}\n\nfunction formatHour24(d, p) {\n return pad(d.getHours(), p, 2);\n}\n\nfunction formatHour12(d, p) {\n return pad(d.getHours() % 12 || 12, p, 2);\n}\n\nfunction formatDayOfYear(d, p) {\n return pad(1 + timeDay.count(timeYear(d), d), p, 3);\n}\n\nfunction formatMilliseconds(d, p) {\n return pad(d.getMilliseconds(), p, 3);\n}\n\nfunction formatMicroseconds(d, p) {\n return formatMilliseconds(d, p) + \"000\";\n}\n\nfunction formatMonthNumber(d, p) {\n return pad(d.getMonth() + 1, p, 2);\n}\n\nfunction formatMinutes(d, p) {\n return pad(d.getMinutes(), p, 2);\n}\n\nfunction formatSeconds(d, p) {\n return pad(d.getSeconds(), p, 2);\n}\n\nfunction formatWeekdayNumberMonday(d) {\n var day = d.getDay();\n return day === 0 ? 7 : day;\n}\n\nfunction formatWeekNumberSunday(d, p) {\n return pad(timeSunday.count(timeYear(d) - 1, d), p, 2);\n}\n\nfunction dISO(d) {\n var day = d.getDay();\n return (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);\n}\n\nfunction formatWeekNumberISO(d, p) {\n d = dISO(d);\n return pad(timeThursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2);\n}\n\nfunction formatWeekdayNumberSunday(d) {\n return d.getDay();\n}\n\nfunction formatWeekNumberMonday(d, p) {\n return pad(timeMonday.count(timeYear(d) - 1, d), p, 2);\n}\n\nfunction formatYear(d, p) {\n return pad(d.getFullYear() % 100, p, 2);\n}\n\nfunction formatYearISO(d, p) {\n d = dISO(d);\n return pad(d.getFullYear() % 100, p, 2);\n}\n\nfunction formatFullYear(d, p) {\n return pad(d.getFullYear() % 10000, p, 4);\n}\n\nfunction formatFullYearISO(d, p) {\n var day = d.getDay();\n d = (day >= 4 || day === 0) ? timeThursday(d) : timeThursday.ceil(d);\n return pad(d.getFullYear() % 10000, p, 4);\n}\n\nfunction formatZone(d) {\n var z = d.getTimezoneOffset();\n return (z > 0 ? \"-\" : (z *= -1, \"+\"))\n + pad(z / 60 | 0, \"0\", 2)\n + pad(z % 60, \"0\", 2);\n}\n\nfunction formatUTCDayOfMonth(d, p) {\n return pad(d.getUTCDate(), p, 2);\n}\n\nfunction formatUTCHour24(d, p) {\n return pad(d.getUTCHours(), p, 2);\n}\n\nfunction formatUTCHour12(d, p) {\n return pad(d.getUTCHours() % 12 || 12, p, 2);\n}\n\nfunction formatUTCDayOfYear(d, p) {\n return pad(1 + utcDay.count(utcYear(d), d), p, 3);\n}\n\nfunction formatUTCMilliseconds(d, p) {\n return pad(d.getUTCMilliseconds(), p, 3);\n}\n\nfunction formatUTCMicroseconds(d, p) {\n return formatUTCMilliseconds(d, p) + \"000\";\n}\n\nfunction formatUTCMonthNumber(d, p) {\n return pad(d.getUTCMonth() + 1, p, 2);\n}\n\nfunction formatUTCMinutes(d, p) {\n return pad(d.getUTCMinutes(), p, 2);\n}\n\nfunction formatUTCSeconds(d, p) {\n return pad(d.getUTCSeconds(), p, 2);\n}\n\nfunction formatUTCWeekdayNumberMonday(d) {\n var dow = d.getUTCDay();\n return dow === 0 ? 7 : dow;\n}\n\nfunction formatUTCWeekNumberSunday(d, p) {\n return pad(utcSunday.count(utcYear(d) - 1, d), p, 2);\n}\n\nfunction UTCdISO(d) {\n var day = d.getUTCDay();\n return (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);\n}\n\nfunction formatUTCWeekNumberISO(d, p) {\n d = UTCdISO(d);\n return pad(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2);\n}\n\nfunction formatUTCWeekdayNumberSunday(d) {\n return d.getUTCDay();\n}\n\nfunction formatUTCWeekNumberMonday(d, p) {\n return pad(utcMonday.count(utcYear(d) - 1, d), p, 2);\n}\n\nfunction formatUTCYear(d, p) {\n return pad(d.getUTCFullYear() % 100, p, 2);\n}\n\nfunction formatUTCYearISO(d, p) {\n d = UTCdISO(d);\n return pad(d.getUTCFullYear() % 100, p, 2);\n}\n\nfunction formatUTCFullYear(d, p) {\n return pad(d.getUTCFullYear() % 10000, p, 4);\n}\n\nfunction formatUTCFullYearISO(d, p) {\n var day = d.getUTCDay();\n d = (day >= 4 || day === 0) ? utcThursday(d) : utcThursday.ceil(d);\n return pad(d.getUTCFullYear() % 10000, p, 4);\n}\n\nfunction formatUTCZone() {\n return \"+0000\";\n}\n\nfunction formatLiteralPercent() {\n return \"%\";\n}\n\nfunction formatUnixTimestamp(d) {\n return +d;\n}\n\nfunction formatUnixTimestampSeconds(d) {\n return Math.floor(+d / 1000);\n}\n","import formatLocale from \"./locale.js\";\n\nvar locale;\nexport var timeFormat;\nexport var timeParse;\nexport var utcFormat;\nexport var utcParse;\n\ndefaultLocale({\n dateTime: \"%x, %X\",\n date: \"%-m/%-d/%Y\",\n time: \"%-I:%M:%S %p\",\n periods: [\"AM\", \"PM\"],\n days: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"],\n shortDays: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n months: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"],\n shortMonths: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n});\n\nexport default function defaultLocale(definition) {\n locale = formatLocale(definition);\n timeFormat = locale.format;\n timeParse = locale.parse;\n utcFormat = locale.utcFormat;\n utcParse = locale.utcParse;\n return locale;\n}\n","import {timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeTicks, timeTickInterval} from \"d3-time\";\nimport {timeFormat} from \"d3-time-format\";\nimport continuous, {copy} from \"./continuous.js\";\nimport {initRange} from \"./init.js\";\nimport nice from \"./nice.js\";\n\nfunction date(t) {\n return new Date(t);\n}\n\nfunction number(t) {\n return t instanceof Date ? +t : +new Date(+t);\n}\n\nexport function calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format) {\n var scale = continuous(),\n invert = scale.invert,\n domain = scale.domain;\n\n var formatMillisecond = format(\".%L\"),\n formatSecond = format(\":%S\"),\n formatMinute = format(\"%I:%M\"),\n formatHour = format(\"%I %p\"),\n formatDay = format(\"%a %d\"),\n formatWeek = format(\"%b %d\"),\n formatMonth = format(\"%B\"),\n formatYear = format(\"%Y\");\n\n function tickFormat(date) {\n return (second(date) < date ? formatMillisecond\n : minute(date) < date ? formatSecond\n : hour(date) < date ? formatMinute\n : day(date) < date ? formatHour\n : month(date) < date ? (week(date) < date ? formatDay : formatWeek)\n : year(date) < date ? formatMonth\n : formatYear)(date);\n }\n\n scale.invert = function(y) {\n return new Date(invert(y));\n };\n\n scale.domain = function(_) {\n return arguments.length ? domain(Array.from(_, number)) : domain().map(date);\n };\n\n scale.ticks = function(interval) {\n var d = domain();\n return ticks(d[0], d[d.length - 1], interval == null ? 10 : interval);\n };\n\n scale.tickFormat = function(count, specifier) {\n return specifier == null ? tickFormat : format(specifier);\n };\n\n scale.nice = function(interval) {\n var d = domain();\n if (!interval || typeof interval.range !== \"function\") interval = tickInterval(d[0], d[d.length - 1], interval == null ? 10 : interval);\n return interval ? domain(nice(d, interval)) : scale;\n };\n\n scale.copy = function() {\n return copy(scale, calendar(ticks, tickInterval, year, month, week, day, hour, minute, second, format));\n };\n\n return scale;\n}\n\nexport default function time() {\n return initRange.apply(calendar(timeTicks, timeTickInterval, timeYear, timeMonth, timeWeek, timeDay, timeHour, timeMinute, timeSecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]), arguments);\n}\n","export default function nice(domain, interval) {\n domain = domain.slice();\n\n var i0 = 0,\n i1 = domain.length - 1,\n x0 = domain[i0],\n x1 = domain[i1],\n t;\n\n if (x1 < x0) {\n t = i0, i0 = i1, i1 = t;\n t = x0, x0 = x1, x1 = t;\n }\n\n domain[i0] = interval.floor(x0);\n domain[i1] = interval.ceil(x1);\n return domain;\n}\n","export default function(x) {\n return function constant() {\n return x;\n };\n}\n","export const abs = Math.abs;\nexport const atan2 = Math.atan2;\nexport const cos = Math.cos;\nexport const max = Math.max;\nexport const min = Math.min;\nexport const sin = Math.sin;\nexport const sqrt = Math.sqrt;\n\nexport const epsilon = 1e-12;\nexport const pi = Math.PI;\nexport const halfPi = pi / 2;\nexport const tau = 2 * pi;\n\nexport function acos(x) {\n return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);\n}\n\nexport function asin(x) {\n return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);\n}\n","import {Path} from \"d3-path\";\n\nexport function withPath(shape) {\n let digits = 3;\n\n shape.digits = function(_) {\n if (!arguments.length) return digits;\n if (_ == null) {\n digits = null;\n } else {\n const d = Math.floor(_);\n if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);\n digits = d;\n }\n return shape;\n };\n\n return () => new Path(digits);\n}\n","import constant from \"./constant.js\";\nimport {abs, acos, asin, atan2, cos, epsilon, halfPi, max, min, pi, sin, sqrt, tau} from \"./math.js\";\nimport {withPath} from \"./path.js\";\n\nfunction arcInnerRadius(d) {\n return d.innerRadius;\n}\n\nfunction arcOuterRadius(d) {\n return d.outerRadius;\n}\n\nfunction arcStartAngle(d) {\n return d.startAngle;\n}\n\nfunction arcEndAngle(d) {\n return d.endAngle;\n}\n\nfunction arcPadAngle(d) {\n return d && d.padAngle; // Note: optional!\n}\n\nfunction intersect(x0, y0, x1, y1, x2, y2, x3, y3) {\n var x10 = x1 - x0, y10 = y1 - y0,\n x32 = x3 - x2, y32 = y3 - y2,\n t = y32 * x10 - x32 * y10;\n if (t * t < epsilon) return;\n t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;\n return [x0 + t * x10, y0 + t * y10];\n}\n\n// Compute perpendicular offset line of length rc.\n// http://mathworld.wolfram.com/Circle-LineIntersection.html\nfunction cornerTangents(x0, y0, x1, y1, r1, rc, cw) {\n var x01 = x0 - x1,\n y01 = y0 - y1,\n lo = (cw ? rc : -rc) / sqrt(x01 * x01 + y01 * y01),\n ox = lo * y01,\n oy = -lo * x01,\n x11 = x0 + ox,\n y11 = y0 + oy,\n x10 = x1 + ox,\n y10 = y1 + oy,\n x00 = (x11 + x10) / 2,\n y00 = (y11 + y10) / 2,\n dx = x10 - x11,\n dy = y10 - y11,\n d2 = dx * dx + dy * dy,\n r = r1 - rc,\n D = x11 * y10 - x10 * y11,\n d = (dy < 0 ? -1 : 1) * sqrt(max(0, r * r * d2 - D * D)),\n cx0 = (D * dy - dx * d) / d2,\n cy0 = (-D * dx - dy * d) / d2,\n cx1 = (D * dy + dx * d) / d2,\n cy1 = (-D * dx + dy * d) / d2,\n dx0 = cx0 - x00,\n dy0 = cy0 - y00,\n dx1 = cx1 - x00,\n dy1 = cy1 - y00;\n\n // Pick the closer of the two intersection points.\n // TODO Is there a faster way to determine which intersection to use?\n if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;\n\n return {\n cx: cx0,\n cy: cy0,\n x01: -ox,\n y01: -oy,\n x11: cx0 * (r1 / r - 1),\n y11: cy0 * (r1 / r - 1)\n };\n}\n\nexport default function() {\n var innerRadius = arcInnerRadius,\n outerRadius = arcOuterRadius,\n cornerRadius = constant(0),\n padRadius = null,\n startAngle = arcStartAngle,\n endAngle = arcEndAngle,\n padAngle = arcPadAngle,\n context = null,\n path = withPath(arc);\n\n function arc() {\n var buffer,\n r,\n r0 = +innerRadius.apply(this, arguments),\n r1 = +outerRadius.apply(this, arguments),\n a0 = startAngle.apply(this, arguments) - halfPi,\n a1 = endAngle.apply(this, arguments) - halfPi,\n da = abs(a1 - a0),\n cw = a1 > a0;\n\n if (!context) context = buffer = path();\n\n // Ensure that the outer radius is always larger than the inner radius.\n if (r1 < r0) r = r1, r1 = r0, r0 = r;\n\n // Is it a point?\n if (!(r1 > epsilon)) context.moveTo(0, 0);\n\n // Or is it a circle or annulus?\n else if (da > tau - epsilon) {\n context.moveTo(r1 * cos(a0), r1 * sin(a0));\n context.arc(0, 0, r1, a0, a1, !cw);\n if (r0 > epsilon) {\n context.moveTo(r0 * cos(a1), r0 * sin(a1));\n context.arc(0, 0, r0, a1, a0, cw);\n }\n }\n\n // Or is it a circular or annular sector?\n else {\n var a01 = a0,\n a11 = a1,\n a00 = a0,\n a10 = a1,\n da0 = da,\n da1 = da,\n ap = padAngle.apply(this, arguments) / 2,\n rp = (ap > epsilon) && (padRadius ? +padRadius.apply(this, arguments) : sqrt(r0 * r0 + r1 * r1)),\n rc = min(abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),\n rc0 = rc,\n rc1 = rc,\n t0,\n t1;\n\n // Apply padding? Note that since r1 β‰₯ r0, da1 β‰₯ da0.\n if (rp > epsilon) {\n var p0 = asin(rp / r0 * sin(ap)),\n p1 = asin(rp / r1 * sin(ap));\n if ((da0 -= p0 * 2) > epsilon) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;\n else da0 = 0, a00 = a10 = (a0 + a1) / 2;\n if ((da1 -= p1 * 2) > epsilon) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;\n else da1 = 0, a01 = a11 = (a0 + a1) / 2;\n }\n\n var x01 = r1 * cos(a01),\n y01 = r1 * sin(a01),\n x10 = r0 * cos(a10),\n y10 = r0 * sin(a10);\n\n // Apply rounded corners?\n if (rc > epsilon) {\n var x11 = r1 * cos(a11),\n y11 = r1 * sin(a11),\n x00 = r0 * cos(a00),\n y00 = r0 * sin(a00),\n oc;\n\n // Restrict the corner radius according to the sector angle. If this\n // intersection fails, it’s probably because the arc is too small, so\n // disable the corner radius entirely.\n if (da < pi) {\n if (oc = intersect(x01, y01, x00, y00, x11, y11, x10, y10)) {\n var ax = x01 - oc[0],\n ay = y01 - oc[1],\n bx = x11 - oc[0],\n by = y11 - oc[1],\n kc = 1 / sin(acos((ax * bx + ay * by) / (sqrt(ax * ax + ay * ay) * sqrt(bx * bx + by * by))) / 2),\n lc = sqrt(oc[0] * oc[0] + oc[1] * oc[1]);\n rc0 = min(rc, (r0 - lc) / (kc - 1));\n rc1 = min(rc, (r1 - lc) / (kc + 1));\n } else {\n rc0 = rc1 = 0;\n }\n }\n }\n\n // Is the sector collapsed to a line?\n if (!(da1 > epsilon)) context.moveTo(x01, y01);\n\n // Does the sector’s outer ring have rounded corners?\n else if (rc1 > epsilon) {\n t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);\n t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);\n\n context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc1, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r1, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);\n context.arc(t1.cx, t1.cy, rc1, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the outer ring just a circular arc?\n else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);\n\n // Is there no inner ring, and it’s a circular sector?\n // Or perhaps it’s an annular sector collapsed due to padding?\n if (!(r0 > epsilon) || !(da0 > epsilon)) context.lineTo(x10, y10);\n\n // Does the sector’s inner ring (or point) have rounded corners?\n else if (rc0 > epsilon) {\n t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);\n t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);\n\n context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);\n\n // Have the corners merged?\n if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t1.y01, t1.x01), !cw);\n\n // Otherwise, draw the two corners and the ring.\n else {\n context.arc(t0.cx, t0.cy, rc0, atan2(t0.y01, t0.x01), atan2(t0.y11, t0.x11), !cw);\n context.arc(0, 0, r0, atan2(t0.cy + t0.y11, t0.cx + t0.x11), atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);\n context.arc(t1.cx, t1.cy, rc0, atan2(t1.y11, t1.x11), atan2(t1.y01, t1.x01), !cw);\n }\n }\n\n // Or is the inner ring just a circular arc?\n else context.arc(0, 0, r0, a10, a00, cw);\n }\n\n context.closePath();\n\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n arc.centroid = function() {\n var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,\n a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi / 2;\n return [cos(a) * r, sin(a) * r];\n };\n\n arc.innerRadius = function(_) {\n return arguments.length ? (innerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : innerRadius;\n };\n\n arc.outerRadius = function(_) {\n return arguments.length ? (outerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : outerRadius;\n };\n\n arc.cornerRadius = function(_) {\n return arguments.length ? (cornerRadius = typeof _ === \"function\" ? _ : constant(+_), arc) : cornerRadius;\n };\n\n arc.padRadius = function(_) {\n return arguments.length ? (padRadius = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), arc) : padRadius;\n };\n\n arc.startAngle = function(_) {\n return arguments.length ? (startAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : startAngle;\n };\n\n arc.endAngle = function(_) {\n return arguments.length ? (endAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : endAngle;\n };\n\n arc.padAngle = function(_) {\n return arguments.length ? (padAngle = typeof _ === \"function\" ? _ : constant(+_), arc) : padAngle;\n };\n\n arc.context = function(_) {\n return arguments.length ? ((context = _ == null ? null : _), arc) : context;\n };\n\n return arc;\n}\n","export var slice = Array.prototype.slice;\n\nexport default function(x) {\n return typeof x === \"object\" && \"length\" in x\n ? x // Array, TypedArray, NodeList, array-like\n : Array.from(x); // Map, Set, iterable, string, or anything else\n}\n","function Linear(context) {\n this._context = context;\n}\n\nLinear.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._point = 0;\n },\n lineEnd: function() {\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n x = +x, y = +y;\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; // falls through\n default: this._context.lineTo(x, y); break;\n }\n }\n};\n\nexport default function(context) {\n return new Linear(context);\n}\n","export function x(p) {\n return p[0];\n}\n\nexport function y(p) {\n return p[1];\n}\n","import array from \"./array.js\";\nimport constant from \"./constant.js\";\nimport curveLinear from \"./curve/linear.js\";\nimport {withPath} from \"./path.js\";\nimport {x as pointX, y as pointY} from \"./point.js\";\n\nexport default function(x, y) {\n var defined = constant(true),\n context = null,\n curve = curveLinear,\n output = null,\n path = withPath(line);\n\n x = typeof x === \"function\" ? x : (x === undefined) ? pointX : constant(x);\n y = typeof y === \"function\" ? y : (y === undefined) ? pointY : constant(y);\n\n function line(data) {\n var i,\n n = (data = array(data)).length,\n d,\n defined0 = false,\n buffer;\n\n if (context == null) output = curve(buffer = path());\n\n for (i = 0; i <= n; ++i) {\n if (!(i < n && defined(d = data[i], i, data)) === defined0) {\n if (defined0 = !defined0) output.lineStart();\n else output.lineEnd();\n }\n if (defined0) output.point(+x(d, i, data), +y(d, i, data));\n }\n\n if (buffer) return output = null, buffer + \"\" || null;\n }\n\n line.x = function(_) {\n return arguments.length ? (x = typeof _ === \"function\" ? _ : constant(+_), line) : x;\n };\n\n line.y = function(_) {\n return arguments.length ? (y = typeof _ === \"function\" ? _ : constant(+_), line) : y;\n };\n\n line.defined = function(_) {\n return arguments.length ? (defined = typeof _ === \"function\" ? _ : constant(!!_), line) : defined;\n };\n\n line.curve = function(_) {\n return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;\n };\n\n line.context = function(_) {\n return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;\n };\n\n return line;\n}\n","import array from \"./array.js\";\nimport constant from \"./constant.js\";\nimport curveLinear from \"./curve/linear.js\";\nimport line from \"./line.js\";\nimport {withPath} from \"./path.js\";\nimport {x as pointX, y as pointY} from \"./point.js\";\n\nexport default function(x0, y0, y1) {\n var x1 = null,\n defined = constant(true),\n context = null,\n curve = curveLinear,\n output = null,\n path = withPath(area);\n\n x0 = typeof x0 === \"function\" ? x0 : (x0 === undefined) ? pointX : constant(+x0);\n y0 = typeof y0 === \"function\" ? y0 : (y0 === undefined) ? constant(0) : constant(+y0);\n y1 = typeof y1 === \"function\" ? y1 : (y1 === undefined) ? pointY : constant(+y1);\n\n function area(data) {\n var i,\n j,\n k,\n n = (data = array(data)).length,\n d,\n defined0 = false,\n buffer,\n x0z = new Array(n),\n y0z = new Array(n);\n\n if (context == null) output = curve(buffer = path());\n\n for (i = 0; i <= n; ++i) {\n if (!(i < n && defined(d = data[i], i, data)) === defined0) {\n if (defined0 = !defined0) {\n j = i;\n output.areaStart();\n output.lineStart();\n } else {\n output.lineEnd();\n output.lineStart();\n for (k = i - 1; k >= j; --k) {\n output.point(x0z[k], y0z[k]);\n }\n output.lineEnd();\n output.areaEnd();\n }\n }\n if (defined0) {\n x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);\n output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);\n }\n }\n\n if (buffer) return output = null, buffer + \"\" || null;\n }\n\n function arealine() {\n return line().defined(defined).curve(curve).context(context);\n }\n\n area.x = function(_) {\n return arguments.length ? (x0 = typeof _ === \"function\" ? _ : constant(+_), x1 = null, area) : x0;\n };\n\n area.x0 = function(_) {\n return arguments.length ? (x0 = typeof _ === \"function\" ? _ : constant(+_), area) : x0;\n };\n\n area.x1 = function(_) {\n return arguments.length ? (x1 = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), area) : x1;\n };\n\n area.y = function(_) {\n return arguments.length ? (y0 = typeof _ === \"function\" ? _ : constant(+_), y1 = null, area) : y0;\n };\n\n area.y0 = function(_) {\n return arguments.length ? (y0 = typeof _ === \"function\" ? _ : constant(+_), area) : y0;\n };\n\n area.y1 = function(_) {\n return arguments.length ? (y1 = _ == null ? null : typeof _ === \"function\" ? _ : constant(+_), area) : y1;\n };\n\n area.lineX0 =\n area.lineY0 = function() {\n return arealine().x(x0).y(y0);\n };\n\n area.lineY1 = function() {\n return arealine().x(x0).y(y1);\n };\n\n area.lineX1 = function() {\n return arealine().x(x1).y(y0);\n };\n\n area.defined = function(_) {\n return arguments.length ? (defined = typeof _ === \"function\" ? _ : constant(!!_), area) : defined;\n };\n\n area.curve = function(_) {\n return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;\n };\n\n area.context = function(_) {\n return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;\n };\n\n return area;\n}\n","import curveLinear from \"./linear.js\";\n\nexport var curveRadialLinear = curveRadial(curveLinear);\n\nfunction Radial(curve) {\n this._curve = curve;\n}\n\nRadial.prototype = {\n areaStart: function() {\n this._curve.areaStart();\n },\n areaEnd: function() {\n this._curve.areaEnd();\n },\n lineStart: function() {\n this._curve.lineStart();\n },\n lineEnd: function() {\n this._curve.lineEnd();\n },\n point: function(a, r) {\n this._curve.point(r * Math.sin(a), r * -Math.cos(a));\n }\n};\n\nexport default function curveRadial(curve) {\n\n function radial(context) {\n return new Radial(curve(context));\n }\n\n radial._curve = curve;\n\n return radial;\n}\n","import curveRadial, {curveRadialLinear} from \"./curve/radial.js\";\nimport line from \"./line.js\";\n\nexport function lineRadial(l) {\n var c = l.curve;\n\n l.angle = l.x, delete l.x;\n l.radius = l.y, delete l.y;\n\n l.curve = function(_) {\n return arguments.length ? c(curveRadial(_)) : c()._curve;\n };\n\n return l;\n}\n\nexport default function() {\n return lineRadial(line().curve(curveRadialLinear));\n}\n","import {pi, sqrt, tau} from \"../math.js\";\n\nexport default {\n draw(context, size) {\n const r = sqrt(size / pi);\n context.moveTo(r, 0);\n context.arc(0, 0, r, 0, tau);\n }\n};\n","import {sqrt} from \"../math.js\";\n\nconst sqrt3 = sqrt(3);\n\nexport default {\n draw(context, size) {\n const y = -sqrt(size / (sqrt3 * 3));\n context.moveTo(0, y * 2);\n context.lineTo(-sqrt3 * y, -y);\n context.lineTo(sqrt3 * y, -y);\n context.closePath();\n }\n};\n","import constant from \"./constant.js\";\nimport {withPath} from \"./path.js\";\nimport asterisk from \"./symbol/asterisk.js\";\nimport circle from \"./symbol/circle.js\";\nimport cross from \"./symbol/cross.js\";\nimport diamond from \"./symbol/diamond.js\";\nimport diamond2 from \"./symbol/diamond2.js\";\nimport plus from \"./symbol/plus.js\";\nimport square from \"./symbol/square.js\";\nimport square2 from \"./symbol/square2.js\";\nimport star from \"./symbol/star.js\";\nimport triangle from \"./symbol/triangle.js\";\nimport triangle2 from \"./symbol/triangle2.js\";\nimport wye from \"./symbol/wye.js\";\nimport times from \"./symbol/times.js\";\n\n// These symbols are designed to be filled.\nexport const symbolsFill = [\n circle,\n cross,\n diamond,\n square,\n star,\n triangle,\n wye\n];\n\n// These symbols are designed to be stroked (with a width of 1.5px and round caps).\nexport const symbolsStroke = [\n circle,\n plus,\n times,\n triangle2,\n asterisk,\n square2,\n diamond2\n];\n\nexport default function Symbol(type, size) {\n let context = null,\n path = withPath(symbol);\n\n type = typeof type === \"function\" ? type : constant(type || circle);\n size = typeof size === \"function\" ? size : constant(size === undefined ? 64 : +size);\n\n function symbol() {\n let buffer;\n if (!context) context = buffer = path();\n type.apply(this, arguments).draw(context, +size.apply(this, arguments));\n if (buffer) return context = null, buffer + \"\" || null;\n }\n\n symbol.type = function(_) {\n return arguments.length ? (type = typeof _ === \"function\" ? _ : constant(_), symbol) : type;\n };\n\n symbol.size = function(_) {\n return arguments.length ? (size = typeof _ === \"function\" ? _ : constant(+_), symbol) : size;\n };\n\n symbol.context = function(_) {\n return arguments.length ? (context = _ == null ? null : _, symbol) : context;\n };\n\n return symbol;\n}\n","function sign(x) {\n return x < 0 ? -1 : 1;\n}\n\n// Calculate the slopes of the tangents (Hermite-type interpolation) based on\n// the following paper: Steffen, M. 1990. A Simple Method for Monotonic\n// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.\n// NOV(II), P. 443, 1990.\nfunction slope3(that, x2, y2) {\n var h0 = that._x1 - that._x0,\n h1 = x2 - that._x1,\n s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),\n s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),\n p = (s0 * h1 + s1 * h0) / (h0 + h1);\n return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;\n}\n\n// Calculate a one-sided slope.\nfunction slope2(that, t) {\n var h = that._x1 - that._x0;\n return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;\n}\n\n// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations\n// \"you can express cubic Hermite interpolation in terms of cubic BΓ©zier curves\n// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1\".\nfunction point(that, t0, t1) {\n var x0 = that._x0,\n y0 = that._y0,\n x1 = that._x1,\n y1 = that._y1,\n dx = (x1 - x0) / 3;\n that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);\n}\n\nfunction MonotoneX(context) {\n this._context = context;\n}\n\nMonotoneX.prototype = {\n areaStart: function() {\n this._line = 0;\n },\n areaEnd: function() {\n this._line = NaN;\n },\n lineStart: function() {\n this._x0 = this._x1 =\n this._y0 = this._y1 =\n this._t0 = NaN;\n this._point = 0;\n },\n lineEnd: function() {\n switch (this._point) {\n case 2: this._context.lineTo(this._x1, this._y1); break;\n case 3: point(this, this._t0, slope2(this, this._t0)); break;\n }\n if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();\n this._line = 1 - this._line;\n },\n point: function(x, y) {\n var t1 = NaN;\n\n x = +x, y = +y;\n if (x === this._x1 && y === this._y1) return; // Ignore coincident points.\n switch (this._point) {\n case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;\n case 1: this._point = 2; break;\n case 2: this._point = 3; point(this, slope2(this, t1 = slope3(this, x, y)), t1); break;\n default: point(this, this._t0, t1 = slope3(this, x, y)); break;\n }\n\n this._x0 = this._x1, this._x1 = x;\n this._y0 = this._y1, this._y1 = y;\n this._t0 = t1;\n }\n}\n\nfunction MonotoneY(context) {\n this._context = new ReflectContext(context);\n}\n\n(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {\n MonotoneX.prototype.point.call(this, y, x);\n};\n\nfunction ReflectContext(context) {\n this._context = context;\n}\n\nReflectContext.prototype = {\n moveTo: function(x, y) { this._context.moveTo(y, x); },\n closePath: function() { this._context.closePath(); },\n lineTo: function(x, y) { this._context.lineTo(y, x); },\n bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }\n};\n\nexport function monotoneX(context) {\n return new MonotoneX(context);\n}\n\nexport function monotoneY(context) {\n return new MonotoneY(context);\n}\n","export function Transform(k, x, y) {\n this.k = k;\n this.x = x;\n this.y = y;\n}\n\nTransform.prototype = {\n constructor: Transform,\n scale: function(k) {\n return k === 1 ? this : new Transform(this.k * k, this.x, this.y);\n },\n translate: function(x, y) {\n return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);\n },\n apply: function(point) {\n return [point[0] * this.k + this.x, point[1] * this.k + this.y];\n },\n applyX: function(x) {\n return x * this.k + this.x;\n },\n applyY: function(y) {\n return y * this.k + this.y;\n },\n invert: function(location) {\n return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];\n },\n invertX: function(x) {\n return (x - this.x) / this.k;\n },\n invertY: function(y) {\n return (y - this.y) / this.k;\n },\n rescaleX: function(x) {\n return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));\n },\n rescaleY: function(y) {\n return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));\n },\n toString: function() {\n return \"translate(\" + this.x + \",\" + this.y + \") scale(\" + this.k + \")\";\n }\n};\n\nexport var identity = new Transform(1, 0, 0);\n\ntransform.prototype = Transform.prototype;\n\nexport default function transform(node) {\n while (!node.__zoom) if (!(node = node.parentNode)) return identity;\n return node.__zoom;\n}\n","export function formatDate(date: Date, format: string): string {\n return format\n .replace(\"YYYY\", String(date.getFullYear()))\n .replace(\"MM\", String(date.getMonth() + 1).padStart(2, \"0\"))\n .replace(\"DD\", String(date.getDate()).padStart(2, \"0\"))\n .replace(\"HH\", String(date.getHours()).padStart(2, \"0\"))\n .replace(\"hh\", String((date.getHours() % 12) || 12).padStart(2, \"0\"))\n .replace(\"mm\", String(date.getMinutes()).padStart(2, \"0\"))\n .replace(\"ss\", String(date.getSeconds()).padStart(2, \"0\"));\n}\n\nexport function formatNumber(value: number, format: string): string {\n // Examples:\n // \"0.00\" = 2 decimals\n if (/0\\.0+/.test(format)) {\n const decimals = format.split(\".\")[1].length;\n return value.toFixed(decimals);\n }\n\n // \"value unit\"\n if (format.includes(\"value\") && format.includes(\"unit\")) {\n return format\n .replace(\"value\", String(value))\n .replace(\"unit\", \"\");\n }\n\n return String(value); // fallback\n}\n\n\nexport function defaultDateFormatter(d: Date): string {\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: true,\n }).format(d);\n}\n","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","import React, { useEffect, useRef, useState } from \"react\";\nimport * as d3 from \"d3\";\n\n\nimport { CSSProperties } from \"react\";\nimport \"../../src/index.css\"\nimport { validateRequiredProps } from \"../helpers/validate\";\nimport { defaultDateFormatter, formatDate, formatNumber } from \"../helpers/formatDate\";\n\nfunction computeBottomMargin(ticks: string[]) {\n if (!ticks.length) return 40;\n\n // estimate width of text based on average character width\n const longest = ticks.reduce((a, b) => (a.length > b.length ? a : b), \"\");\n const approxCharWidth = 7; // px\n const approximateTextWidth = longest.length * approxCharWidth;\n\n // because labels rotate -30deg, height β‰ˆ width * sin(30Β°)\n const estimatedHeight = approximateTextWidth * 0.5;\n\n return Math.max(40, estimatedHeight + 20); // + extra padding\n}\n\n/* ------------------------ Types ------------------------ */\nexport interface ChartDataPoint {\n timestamp: number;\n value: number;\n}\ntype WidgetState = {\n value?: any;\n loading?: boolean;\n error?: string | null; // βœ… matches your React state\n};\n\n\ninterface ChartStyleSet {\n container?: CSSProperties;\n title?: CSSProperties;\n tooltip?: CSSProperties;\n axis?: CSSProperties;\n chart?: {\n strokeColor?: string;\n strokeWidth?: number;\n gradientColors?: [string, string];\n dotRadius?: number;\n };\n fontFamily:string\n}\ntype StylesInput =\n | ChartStyleSet\n | ((state: WidgetState) => ChartStyleSet);\n\nexport interface ChartWidgetProps {\n client: any;\n nodeId: string;\n variable: string;\n from:number,\n to:number,\n limit?:number,\n title?: string;\n styles?: StylesInput;\n tooltipFormatter?: (d: ChartDataPoint) => string;\n tickCount?: number; // number of ticks on x axis (default: 4)\n tickFormatter?: (d: Date) => string; // optional custom formatter\n xTickFormat?: string | ((d: Date) => string); // date formatting\n yTickFormat?: string | ((v: number) => string); // numeric formatting\n tooltipFormat?: string | ((d: ChartDataPoint) => string);\n onStyleChange?:(data:ChartDataPoint[]) =>{}\n}\n\n/* ------------------------ Helpers ------------------------ */\nconst normalizeSx = (sx: Record | undefined): Record => {\n if (!sx) return {};\n if (Array.isArray(sx)) return Object.assign({}, ...sx);\n if (typeof sx === \"function\") return sx({}) as Record;\n return sx as Record;\n};\n\nconst toDateSafe = (ts: number): Date => {\n // If ts < 1e12, treat as seconds -> convert to ms\n if (ts < 1e12) return new Date(ts * 1000);\n\n return new Date(ts);\n};\n\n/* ------------------------ Defaults ------------------------ */\nconst defaultFontFamily = \"Roboto, sans-serif\";\n\nconst defaultStyles: Required = {\n container: {\n width: 400,\n height: 250,\n padding: 2,\n margin: 0,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",\n borderRadius: 10,\n boxSizing: \"border-box\",\ngap:0,\n background: \"rgb(248, 249, 250)\",\n border: \"1px solid rgba(211, 216, 220, 1)\",\n \n\n textAlign: \"center\",\n fontFamily: defaultFontFamily,\n },\n title: {\n \n fontWeight: 600,\n color: \"rgba(0,0,0,0.75)\",\n // marginBottom: 1,\n fontFamily: defaultFontFamily,\n },\n tooltip: {\n background: \"rgba(0,0,0,0.75)\",\n\n color: \"#ffffff\",\n\n borderRadius: \"6px\",\n padding: \"6px 10px\",\n fontSize: \"12px\",\n fontFamily: defaultFontFamily,\n },\n axis: {\n color: \"#666\",\n fontSize: \"11px\",\n fontFamily:defaultFontFamily,\n\n },\n chart: {\n strokeColor: \"#1e88e5\",\n strokeWidth: 2,\n gradientColors: [\"#1e88e5\", \"#90caf9\"],\n dotRadius: 4,\n\n },\n fontFamily:defaultFontFamily\n\n \n};\n\n\n// ---- ChartWidget ----\nexport const ChartWidget: React.FC = ({\n client,\n nodeId,\n variable,\n from,\n to,\n limit=20,\n title = \"Latest Data\",\n styles = {},\n tooltipFormatter = (d) =>\n `${new Date(\n new Date(d.timestamp < 1e12 ? d.timestamp * 1000 : d.timestamp)\n ).toLocaleString(undefined, {\n month: \"short\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: true,\n })}: ${d.value}`,\n tickCount = 4,\n tickFormatter,\n xTickFormat,\n yTickFormat,\n tooltipFormat,\n onStyleChange\n}) => {\n\n validateRequiredProps(\n \"Chart Widget\",\n { client, nodeId, variable,from,to },\n [\"client\", \"nodeId\", \"variable\",\"from time\",\"to time\"]\n );\n\n const resolvedXFormatter =\n typeof xTickFormat === \"string\"\n ? (d: Date) => formatDate(d, xTickFormat)\n : xTickFormat;\n\nconst resolvedYFormatter =\n typeof yTickFormat === \"string\"\n ? (v: number) => formatNumber(v, yTickFormat)\n : yTickFormat;\n\nconst resolvedTooltipFormatter =\n typeof tooltipFormat === \"string\"\n ? (d: ChartDataPoint) =>\n `${formatDate(toDateSafe(d.timestamp), tooltipFormat)}: ${d.value}`\n : tooltipFormat;\n\n\n // Refs + state\n const svgRef = useRef(null);\n const tooltipNodeRef = useRef(null);\n const [data, setData] = useState([\n // { timestamp: Date.now() - 60000, value: 33 },\n // { timestamp: Date.now() - 30000, value: 44 },\n // { timestamp: Date.now(), value: 38 },\n ]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(null);\n const [node, setNode] = useState(null);\n\n\n const state = { data, loading, error }; // <-- your widget’s internal state\n\n// Resolve function or static style object\nconst [dynamicStyles, setDynamicStyles] = useState>({});\n\nconst baseResolvedStyles =\n typeof styles === \"function\" ? styles(state) : styles || {};\n\nconst resolvedStyles = {\n container: { ...baseResolvedStyles.container, ...dynamicStyles?.container },\n title: { ...baseResolvedStyles.title, ...dynamicStyles?.title },\n tooltip: { ...baseResolvedStyles.tooltip, ...dynamicStyles?.tooltip },\n chart: { ...baseResolvedStyles.chart, ...dynamicStyles?.chart },\n axis: { ...baseResolvedStyles.axis, ...dynamicStyles?.axis },\n fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily,\n};\n const mountedRef = useRef(false);\n const failureCountRef = useRef(0);\n const isFetchingRef = useRef(false);\n const MAX_FAILURES = 3;\n\n // ---- Normalize Styles ----\n const containerSx = normalizeSx(resolvedStyles?.container);\n const titleSx = normalizeSx(resolvedStyles?.title);\n const tooltipSx = normalizeSx(resolvedStyles?.tooltip);\n const chartSx = resolvedStyles.chart ?? {};\n const axisSx = normalizeSx(resolvedStyles?.axis);\n\n // --- Container dimensions with TypeScript-safe default ---\n const containerDefaults: any = defaultStyles.container!;\n const width = containerSx.width ?? containerDefaults.width;\n const height = containerSx.height ?? containerDefaults.height;\n\n\n // --- Font family handling ---\n const globalFontFamily = resolvedStyles?.fontFamily ?? \"Roboto\";\n const labelFontFamily = titleSx.fontFamily ?? globalFontFamily;\n\n\n \n\n\n\n\n // --- Scaled font sizes ---\n const baseFont = Math.min(Number(width), Number(height)) * 0.15;\n\n // --- Compute font sizes dynamically if not provided by user ---\n const labelFont = (resolvedStyles?.title as any)?.fontSize ?? baseFont * 0.6;\n\n \n const strokeColor = chartSx.strokeColor ?? defaultStyles.chart.strokeColor;\n const strokeWidth = chartSx.strokeWidth ?? defaultStyles.chart.strokeWidth;\n const gradientColors =\n chartSx.gradientColors ?? defaultStyles.chart.gradientColors;\nconst dotRadius = chartSx.dotRadius ?? defaultStyles.chart.dotRadius;\n // ---- Fetch Node ----\n useEffect(() => {\n if (!client || !nodeId) return;\n const anedya = (client as any)._anedya;\n const createdNode = anedya?.NewNode?.(client, nodeId);\n setNode(createdNode);\n }, [client, nodeId]);\n\n // ---- Fetch Data ----\n useEffect(() => {\n mountedRef.current = true;\n if (\n !node\n // || data.length>0\n )\n return;\n\n const fetchData = async () => {\n if (isFetchingRef.current || failureCountRef.current >= MAX_FAILURES)\n return;\n isFetchingRef.current = true;\n\n try {\n setLoading(true);\n setError(null);\n // const currentTime = Date.now();\n // const twentyFourHoursAgo = currentTime - 86400 * 1000;\n//1732420983000\n//1763956983000\n const req = {\n variable,\n from: from,\n to: to,\n limit: limit,\n order: \"asc\",\n };\n const res = await node.getData(req);\n\n if (!mountedRef.current) return;\n\n if (res.isSuccess && res.isDataAvailable) {\n setData(res.data);\n setError(\"\");\n\n } else {\n console.error(\"error fetching data:\", res.error);\n setError(res.error.errorMessage);\n }\n failureCountRef.current = 0;\n } catch (err: any) {\n console.error(\"Error fetching chart data:\", err);\n setData([]);\n setError(err?.message ?? \"Failed to fetch data\");\n failureCountRef.current += 1;\n } finally {\n setLoading(false);\n if (mountedRef.current) isFetchingRef.current = false;\n }\n };\n\n fetchData();\n return () => {\n mountedRef.current = false;\n };\n }, [node, variable]);\n\n /* ------------------------ D3 render (dots + line + area + tooltip + axes) ------------------------ */\n useEffect(() => {\n if (!svgRef.current) return;\n const svgEl = svgRef.current;\n const svg = d3.select(svgEl);\n svg.selectAll(\"*\").remove();\n\n // If no data, nothing to draw\n if (!data || data.length === 0) {\n return;\n }\n\n\n\n // // --- COMPUTE SCALES --- //\n // const tempDates = data.map((d) => toDateSafe(d.timestamp));\n // const tempX = d3.scaleTime().domain(d3.extent(tempDates) as [Date, Date]).range([0, 1]); // temp range\n // const provisionalTicks = tempX.ticks(tickCount);\n\n // const tickLabels = provisionalTicks.map((d) =>\n // resolvedXFormatter ? resolvedXFormatter(d) : defaultDateFormatter(d)\n // );\n\n // const dynamicBottom = computeBottomMargin(tickLabels);\n\n // // --- NOW REAL MARGINS --- //\n // const margin = { top: 20, right: 20, bottom: dynamicBottom, left: 50 };\n\n // // recompute chart area\n // const chartW = Math.max(10, width - margin.left - margin.right);\n // const chartH = Math.max(10, height - margin.top - margin.bottom);\n\n // // recompute x with real width\n // tempX.range([0, chartW]);\n\n //.attr(\"transform\", \"rotate(-30)\")\n//margins (leave extra bottom space for rotated ticks)\n const margin = { top: 20, right: 20, bottom: 130, left: 50 };\n const chartW = Math.max(10, width - margin.left - margin.right);\n const chartH = Math.max(10, height - margin.top - margin.bottom);\n\n // group\n const g = svg.append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n // parse / convert timestamps to Date safely\n const dates = data.map((d) => toDateSafe(d.timestamp));\n const x = d3.scaleTime().domain(d3.extent(dates) as [Date, Date]).range([0, chartW]);\n const maxY = Math.max(10, d3.max(data, (d) => Number(d.value)) ?? 10);\n const y = d3.scaleLinear().domain([0, maxY]).nice().range([chartH, 0]);\n\n // gradient\n const safeGradient = gradientColors ?? [\"#1e88e5\", \"#90caf9\"];\n const safeStroke = strokeColor ?? \"#1e88e5\";\n const safeWidth = strokeWidth ?? 2;\n const safeDotRadius = dotRadius ?? 4\n const defs = svg.append(\"defs\");\n\n const gradient = defs\n .append(\"linearGradient\")\n .attr(\"id\", \"chartGradient\")\n .attr(\"x1\", \"0%\")\n .attr(\"y1\", \"0%\")\n .attr(\"x2\", \"0%\")\n .attr(\"y2\", \"100%\");\n gradient\n .append(\"stop\")\n .attr(\"offset\", \"0%\")\n .attr(\"stop-color\", safeGradient[0])\n .attr(\"stop-opacity\", 0.5);\n gradient\n .append(\"stop\")\n .attr(\"offset\", \"100%\")\n .attr(\"stop-color\", safeGradient[1])\n .attr(\"stop-opacity\", 0);\n\n // area\n const area = d3\n .area()\n .x((d) => x(toDateSafe(d.timestamp)))\n .y0(chartH)\n .y1((d) => y(d.value))\n .curve(d3.curveMonotoneX);\n\n g.append(\"path\").datum(data).attr(\"fill\", \"url(#chartGradient)\").attr(\"d\", area);\n\n // line\n const line = d3\n .line()\n .x((d) => x(toDateSafe(d.timestamp)))\n .y((d) => y(d.value))\n .curve(d3.curveMonotoneX);\n\n g.append(\"path\")\n .datum(data)\n .attr(\"fill\", \"none\")\n .attr(\"stroke\", safeStroke)\n .attr(\"stroke-width\", safeWidth)\n .attr(\"d\", line);\n\n // dots\n const dotR = computeDotRadius(chartW, chartH, safeDotRadius);\n const dots = g\n .selectAll(\".dot\")\n .data(data)\n .enter()\n .append(\"circle\")\n .attr(\"class\", \"dot\")\n .attr(\"cx\", (d) => x(toDateSafe(d.timestamp)))\n .attr(\"cy\", (d) => y(d.value))\n .attr(\"r\", dotR)\n .attr(\"fill\", safeStroke)\n .style(\"cursor\", \"default\");\n\n // Tooltip (create single DOM node appended to body)\n // Reuse tooltip div if present\n let tooltipDiv = tooltipNodeRef.current;\n if (!tooltipDiv) {\n tooltipDiv = document.createElement(\"div\");\n tooltipNodeRef.current = tooltipDiv;\n document.body.appendChild(tooltipDiv);\n }\n // apply tooltip styles (inline)\n const tooltipDefaults: any = defaultStyles.tooltip;\n tooltipDiv.style.position = \"absolute\";\n tooltipDiv.style.pointerEvents = \"none\";\n tooltipDiv.style.opacity = \"0\";\n tooltipDiv.style.background = (tooltipSx.backgroundColor ?? tooltipDefaults.background) as string;\n tooltipDiv.style.color = (tooltipSx.color ?? tooltipDefaults.color) as string;\n tooltipDiv.style.borderRadius = (tooltipSx.borderRadius ?? tooltipDefaults.borderRadius) as string;\n tooltipDiv.style.padding = (tooltipSx.padding ?? tooltipDefaults.padding) as string;\n tooltipDiv.style.fontSize = (tooltipSx.fontSize ?? tooltipDefaults.fontSize) as string;\n tooltipDiv.style.transition = \"opacity 120ms\";\n\n // interactions\n dots\n .on(\"mouseover\", function (event, d: ChartDataPoint) {\n tooltipDiv!.style.opacity = \"1\";\n tooltipDiv!.innerHTML = resolvedTooltipFormatter\n ? resolvedTooltipFormatter(d)\n : tooltipFormatter(d);\n })\n .on(\"mousemove\", function (event) {\n // place tooltip near pointer but keep inside window\n const pad = 8;\n const left = Math.min(window.innerWidth - 200, event.pageX + pad);\n const top = Math.max(8, event.pageY - 36);\n tooltipDiv!.style.left = `${left}px`;\n tooltipDiv!.style.top = `${top}px`;\n })\n .on(\"mouseout\", function () {\n tooltipDiv!.style.opacity = \"0\";\n });\n\n // axes - bottom x with custom tick formatting and rotated labels\n const xAxis = d3\n .axisBottom(x)\n .ticks(tickCount)\n .tickFormat((d) => {\n if (resolvedXFormatter) return resolvedXFormatter(d as Date);\n return defaultDateFormatter(d as Date);\n });\n\n\n const axisDefaults : any = defaultStyles.axis\n g.append(\"g\")\n .attr(\"transform\", `translate(0,${chartH})`)\n .call(xAxis)\n .selectAll(\"text\")\n .attr(\"transform\", \"rotate(-30)\")\n .style(\"text-anchor\", \"end\")\n .style(\"font-size\", (axisSx.fontSize ?? axisDefaults.fontSize) as string)\n .style(\"fill\", (axisSx.color ?? axisDefaults.color) as string)\n .style(\"font-family\", (axisSx.fontFamily ?? axisDefaults.fontFamily) as string);\n\n g.append(\"g\")\n .call(d3.axisLeft(y).ticks(5).tickFormat((v) => {\n if (resolvedYFormatter) return resolvedYFormatter(v as number);\n return String(v);\n }))\n .selectAll(\"text\")\n .style(\"font-size\", (axisSx.fontSize ?? axisDefaults.fontSize) as string)\n .style(\"fill\", (axisSx.color ?? axisDefaults.color) as string)\n .style(\"font-family\", (axisSx.fontFamily ?? axisDefaults.fontFamily) as string);\n\n // keep axes inside container by clipping overflow\n // Add clipPath so elements don't overflow container boundaries visually\n const clipId = `clip-${Math.random().toString(36).slice(2, 9)}`;\n svg\n .append(\"defs\")\n .append(\"clipPath\")\n .attr(\"id\", clipId)\n .append(\"rect\")\n .attr(\"width\", width)\n .attr(\"height\", height);\n svg.attr(\"clip-path\", `url(#${clipId})`);\n\n // cleanup on effect re-run\n return () => {\n // remove tooltip div if created by this component\n if (tooltipNodeRef.current) {\n try {\n tooltipNodeRef.current.remove();\n } catch {}\n tooltipNodeRef.current = null;\n }\n svg.selectAll(\"*\").remove();\n };\n }, [\n data,\n width,\n height,\n strokeColor,\n strokeWidth,\n gradientColors,\n dotRadius,\n tickCount,\n tickFormatter,\n tooltipFormatter,\n axisSx,\n tooltipSx,\n ]);\n\n\n\n // Whenever value changes, allow user to modify styles dynamically\n useEffect(() => {\n if (typeof onStyleChange === \"function\") {\n const updated = onStyleChange(data);\n if (updated && typeof updated === \"object\") {\n setDynamicStyles(updated);\n }\n }\n }, [data]);\n \n /* ------------------------ Helpers ------------------------ */\n function computeDotRadius(chartW: number, chartH: number, requested: number) {\n // scale dot radius a bit relative to min dimension but honor requested if provided\n const base = Math.max(2, Math.min(chartW, chartH) * 0.012);\n return requested ?? Math.round(base);\n }\n // --- Merge styles safely ---\n const mergedContainerSx: CSSProperties = {\n ...defaultStyles.container,\n ...containerSx,\n \n };\n const mergedLabelSx: CSSProperties = {\n ...defaultStyles.title,\n fontSize: labelFont,\n ...titleSx,\n fontFamily: labelFontFamily,\n };\n\n\n return (\n
\n {title && (\n \n {title}\n \n )}\n {loading ? (\n \n
\n \n ) : error ? (\n
\n \n{error}\n
\n\n \n ) : data?.length === 0?\n
\n \n{ \"No data available\"}\n
\n\n :\n (\n \n )}\n \n );\n};\n\n//add customizable toolips, stroke width and color, and title obvs , timestamps for get data request\n//match customization and failsafes to latest data\n//documentation\n//modify anedya client as well\n//adjust rateLimitMs\n//how do i also ensure that the y axis labels dont crpss the container card border , all labels are contained within th container card\n\n//ftick format functions\n//responsiveness\n//frequesncy of ticks\n//show all widgets\n//documentation\n//consistent widget default styling , default color palette and theme\n//beta launch\n//how to add docs in npm --- add them in read me\n","export default function extent(values, valueof) {\n let min;\n let max;\n if (valueof === undefined) {\n for (const value of values) {\n if (value != null) {\n if (min === undefined) {\n if (value >= value) min = max = value;\n } else {\n if (min > value) min = value;\n if (max < value) max = value;\n }\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null) {\n if (min === undefined) {\n if (value >= value) min = max = value;\n } else {\n if (min > value) min = value;\n if (max < value) max = value;\n }\n }\n }\n }\n return [min, max];\n}\n","export default function max(values, valueof) {\n let max;\n if (valueof === undefined) {\n for (const value of values) {\n if (value != null\n && (max < value || (max === undefined && value >= value))) {\n max = value;\n }\n }\n } else {\n let index = -1;\n for (let value of values) {\n if ((value = valueof(value, ++index, values)) != null\n && (max < value || (max === undefined && value >= value))) {\n max = value;\n }\n }\n }\n return max;\n}\n","import React, { PureComponent, SVGProps } from \"react\";\n\nclass SVGBase extends PureComponent> {\n render() {\n const { children, ...props } = this.props;\n return {children};\n }\n}\n\nexport default SVGBase;\n","import React, { PureComponent } from \"react\";\nimport { line, scaleLinear } from \"d3\";\n\n\n\nclass Pointer extends PureComponent {\n render() {\n const {\n width = 12.5,\n head = (0.8 * 250) / 2 - 5,\n tail = 5,\n value = -5,\n tooltip = \"\",\n center = { x: 125, y: 135 },\n minAngle,\n maxAngle,\n disabled\n } :any= this.props;\n\n const pointerLine = line()([\n [width / 2, 0],\n [0, -head],\n [-(width / 2), 0],\n [0, tail],\n [width / 2, 0]\n ]);\n const valueScale = scaleLinear()\n .domain([0, 1])\n .range([minAngle, maxAngle]);\n const pointerValue = valueScale(value);\n\n const showTooltip = (e: React.MouseEvent, text: string) => {\n const tooltip = document.getElementById(\"gauge-tooltip\");\n if (!tooltip || !text) return;\n\n tooltip.textContent = text;\n tooltip.style.opacity = \"1\";\n tooltip.style.transform = \"translateY(0px)\";\n moveTooltip(e);\n};\n\nconst moveTooltip = (e: React.MouseEvent) => {\n const tooltip = document.getElementById(\"gauge-tooltip\");\n if (!tooltip) return;\n\n tooltip.style.left = e.clientX + 10 + \"px\";\n tooltip.style.top = e.clientY - 20 + \"px\";\n};\n\nconst hideTooltip = () => {\n const tooltip = document.getElementById(\"gauge-tooltip\");\n if (!tooltip) return;\n\n tooltip.style.opacity = \"0\";\n tooltip.style.transform = \"translateY(-5px)\";\n};\n\n return (\n // \n \n showTooltip(e, tooltip)}\n onMouseMove={(e) => moveTooltip(e)}\n onMouseLeave={hideTooltip}\n >\n {tooltip && {tooltip}}\n \n \n // \n );\n }\n}\n\nexport default Pointer;\n","import React, { PureComponent } from \"react\";\nimport { symbol, symbolTriangle } from \"d3\";\n\nclass InvertedTriangle extends PureComponent {\n render() {\n const { center, disabled }:any = this.props;\n return (\n \n );\n }\n}\n\nexport default InvertedTriangle;\n","import React, { PureComponent } from \"react\";\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\n\n const renderUnitText = (text: string, style: UnitStyle) => {\n switch (style) {\n case \"superscript\":\n return {text};\n case \"subscript\":\n return {text};\n default:\n return {text};\n }\n};\n\nclass UnitOfMeasurement extends PureComponent {\n render() {\n const { value, disabled, center, offsetText,uom ,mergedValueSx,mergedUnitSx ,formatted,...rest}:any = this.props;\n\n return (\n // \n // {value+\" \"+uom}\n // \n\n \n \n {/* UNIT LEFT */}\n {formatted.unitText && formatted.position === \"left\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n\n {/* VALUE */}\n
{formatted.text}
\n\n {/* UNIT RIGHT */}\n {formatted.unitText && formatted.position === \"right\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n\n {/* UNIT TOP */}\n {formatted.unitText && formatted.position === \"top\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n\n {/* UNIT BOTTOM */}\n {formatted.unitText && formatted.position === \"bottom\" && (\n
\n {renderUnitText(formatted.unitText, formatted.unitStyle!)}\n
\n )}\n \n \n );\n }\n}\n\nexport default UnitOfMeasurement;\n","import React, { PureComponent } from \"react\";\nimport { scaleLinear, lineRadial } from \"d3\";\n\n/** Ratio of arc to size of container. */\nconst baseRatio = 0.8;\n\n/** Resolution of arc. */\nconst length = 40;\n\nclass GaugeArc extends PureComponent {\n render() {\n const {\n inset = 0,\n min = 0,\n max = 1,\n maxAngle,\n minAngle,\n center = { x: 125, y: 135 },\n ...props\n }:any = this.props;\n\n /** Calculate max angle of arc from degrees to radians */\n const maxRatio = maxAngle / 180;\n const arcMax = Math.PI * maxRatio;\n\n /** Calculate min angle of arc from degrees to radians */\n const minRatio = minAngle / 180;\n const arcMin = Math.PI * minRatio;\n\n /** Linear map from [0,1] to [-135,135] degrees in radians */\n const refToRads = scaleLinear()\n .domain([0, 1])\n .range([arcMin, arcMax]);\n\n /** Render scale to map [0,length - 1] to [minAndle, maxAngle] for rendering */\n const arcScale = scaleLinear()\n .domain([0, length - 1])\n .range([refToRads(min), refToRads(max)]);\n\n /** Actual path function to generate path. */\n const arc:any = lineRadial()\n .angle((d, i) => arcScale(i))\n .radius((250 * baseRatio) / 2 - inset);\n\n const arcPath = arc({ length });\n\n return (\n \n );\n }\n}\n\nexport default GaugeArc;\n","import React, { PureComponent } from \"react\";\nimport { scaleLinear, line } from \"d3\";\n\nconst getTickRef = (tickCount:any, minVal:any, maxVal:any, minAngle:any, maxAngle:any) => {\n if (tickCount % 2 === 0)\n console.warn(\n \"Ticks should be odd numbered to ensure a tick in in the middle of the gauge.\"\n );\n\n const idxToRef = scaleLinear()\n .domain([0, tickCount - 1])\n .range([0, 1]);\n\n const idxToVal = scaleLinear()\n .domain([0, tickCount - 1])\n .range([minVal, maxVal]);\n\n const refToDeg = scaleLinear()\n .domain([0, 1])\n .range([minAngle, maxAngle]);\n\n return [...Array(tickCount)].map((v, i) => ({\n index: i,\n val: idxToVal(i),\n deg: refToDeg(idxToRef(i))\n }));\n};\n\nconst tickLineLong = line()\n .x(0)\n .y((d, i) => i)(Array.from({ length: 35 }));\n\nconst tickLineShort = line()\n .x(0)\n .y((d, i) => i)(Array.from({ length: 12 }));\n\nclass Label extends PureComponent {\n render() {\n const {\n disabled,\n center,\n tickCount,\n min,\n max,\n maxAngle,\n minAngle,\n offsetText,\n length = 300 / 2 - 30\n }:any = this.props;\n\n const ticks = getTickRef(tickCount, min, max, minAngle, maxAngle);\n\n return ticks.map(({ val, deg, index }) => {\n return (\n \n \n \n {Number(val)}\n \n \n );\n });\n }\n}\n\nexport default Label;\n","import React, { PureComponent } from \"react\";\n\nclass Gradient extends PureComponent {\n render() {\n const { start, end, id, disabled }:any = this.props;\n return (\n \n \n \n \n \n \n );\n }\n}\n\nexport default Gradient;\n","import React, { useCallback, useMemo } from \"react\";\nimport { scaleLinear } from \"d3\";\n\nimport {\n SVGBase,\n Pointer,\n InvertedTriangle,\n UnitOfMeasurement,\n GaugeArc,\n Label\n} from \"./components\";\n\nimport \"../../index.css\"\nconst defaultSize = 250;\n\nconst Gauge = ({\n height=400,\n width=400,\n disabled=false,\n value = -1,\n min = 0,\n max = 100,\n maxAngle = 135,\n minAngle = -135,\n tickCount = 5,\n arcSegments = [{ min: 0, max: 1, color: \"skyblue\" }],\n labelProps = {\n offsetText: -7.5\n },\n uom = \"\",\n uomProps = {\n offsetText: -10,\n //-7.5\n },\n pointerLabel = \"\",\n mergedUnitSx={},\n mergedValueSx={},\n formatted,\n ...props\n}:any) => {\n const gaugeOrigin = {\n x: 140,\n y: 140\n };\n\n const valueScale = useCallback(\n scaleLinear()\n .domain([min, max])\n .range([0, 1]),\n [min, max]\n );\n\n /** Value scaled to [0,1] */\n const valueRef = useMemo(() => valueScale(value), [value, valueScale]);\n\n return (\n <>\n \n \n \n {arcSegments.map(({ min, max, color}:any, idx:any) => (\n \n {/* {typeof node === \"function\" ? node(disabled) : node} */}\n \n \n ))}\n \n \n \n \n \n );\n};\n\nexport default Gauge;\n","\n// GaugeWidget.tsx\nimport React, { useEffect, useRef, useMemo, useState } from \"react\";\nimport * as d3 from \"d3\";\n\nimport ReactDOM from \"react-dom\";\n\nimport Gauge from \"../components/Gauge/Gauge\";\nimport useGradient from \"../components/Gauge/hooks/useGradient\";\nimport { CSSProperties } from \"react\";\nimport { Anedya } from \"@anedyasystems/anedya-frontend-sdk\";\nimport { validateRequiredProps } from \"../helpers/validate\";\n\n/**\n * Helper: Normalize SxProps to plain object (like in your other widgets)\n */\nconst normalizeSx = (\n sx: Record | undefined\n): Record => {\n if (!sx) return {};\n if (Array.isArray(sx)) return Object.assign({}, ...sx);\n if (typeof sx === \"function\") return sx({}) as Record;\n return sx as Record;\n};\nconst defaultFontFamily = \"Roboto, sans-serif\";\n\ninterface GaugeArcStyle {\n trackColor?: string;\n progressColor?: string;\n progressStroke?: string;\n fontSize?: string | number;\n fontFamily?: string;\n}\n\nconst defaultArcSx: GaugeArcStyle = {\n trackColor: \"#e6e6e6\", // light background arc\n progressColor: \"#4caf50\", // the β€œfilled” arc part\n progressStroke: \"none\",\n fontSize: \"20px\",\n fontFamily: defaultFontFamily,\n};\nconst defaultSubtitleSx: CSSProperties = {\n fontSize: \"12px\",\n color: \"#666\",\n fontFamily: defaultFontFamily,\n};\n\n\n/* ---------------------- Types ---------------------- */\n\nexport interface Zone {\n from: number; // inclusive\n to: number; // exclusive\n color: string;\n}\ntype WidgetState = {\n value?: any;\n loading?: boolean;\n error?: string | null; // βœ… matches your React state\n};\n\nexport interface GaugeStyleSet {\n container?: CSSProperties;\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\nsubtitle?: CSSProperties;\n arc?: GaugeArcStyle; \n fontFamily?: string; // optional global font family for all 3\n}\n\n\ntype StylesInput =\n | GaugeStyleSet\n | ((state: WidgetState) => GaugeStyleSet);\n\n\n\nexport interface GaugeMetrics {\n maxRadius: number;\n valueAngleDeg: number;\n valueAngleRad: number;\n startAngleDeg: number;\n endAngleDeg: number;\n innerRadius: number;\n outerRadius: number;\n cx: number;\n cy: number;\n}\n\nexport interface GaugeWidgetProps {\n client: any;\n nodeId: string;\n variable: string;\n min?: number; // default 0\n max?: number; // default 100\n startAngleDeg?: number; // degrees, default -90 (left) for semi-circle\n endAngleDeg?: number; // degrees, default 90 (right) for semi-circle\n thickness?: number; // thickness of the arc (absolute px) β€” default: 0.2 * radius\n zones?: Zone[]; // colored zones, optional (defaults provided)\n showNeedle?: boolean; // draw a needle for the value\n needleColor?: string;\n needleWidth?: number;\n title?: string;\n subtitle?: string;\nstyles?: StylesInput;\n disabled?: boolean; //for pointer label\n tickCount?: number;\n unit?: string;\n uomOffset?: number;\n labelOffset?: number;\n // callback to receive computed values (optional)\n onMetrics?: (metrics: GaugeMetrics) => void;\n // function that returns the inner text (defaults to \"value / max\")\n valueText?: (opts: {\n value?: number;\n valueMin: number;\n valueMax: number;\n }) => string;\n onStyleChange?:(value:number) =>{};\n displayText?: DisplayTextFormatter;\n}\n\ntype UnitPosition = \"left\" | \"right\" | \"top\" | \"bottom\";\ntype UnitStyle = \"normal\" | \"subscript\" | \"superscript\";\n\n\ninterface DisplayTextResult {\n text: string;\n unitText?: string;\n position?: UnitPosition;\n unitStyle?: UnitStyle;\n}\n\ntype DisplayTextFormatter = (\n value: number,\n unit?: string\n) => DisplayTextResult;\n\n\n/* ---------------------- Defaults ---------------------- */\n\nconst defaultZones: Zone[] = [\n { from: 0, to: 40, color: \"#4caf50\" }, // green\n { from: 40, to: 60, color: \"#ffeb3b\" }, // yellow\n { from: 60, to: 100, color: \"#f44336\" }, // red\n];\n\n// --- Default styles ---\ninterface StyleSet {\n\n label?: CSSProperties;\n value?: CSSProperties;\n unit?: CSSProperties;\n fontFamily?: string; // optional global font family for all 3\n}\n\nconst defaultContainerSx: any = {\n width: 400,\n height: 250,\n padding: 2,\n margin: 0,\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"flex-start\",\n alignItems: \"center\",\n borderRadius: 10,\n boxSizing: \"border-box\",\n background: \"rgb(248, 249, 250)\",\n border: \"1px solid rgba(211, 216, 220, 1)\",\n//'linear-gradient(to right, rgb(47, 99, 255), rgb(20, 110, 180))'\n fontFamily: defaultFontFamily,\n color:\"#000000\",\n overflowWrap: \"break-word\",\n label: { fontWeight: 500, color: \"#000000\", fontFamily: defaultFontFamily },\n value: { fontWeight: 700, color: \"#000000\", fontFamily: defaultFontFamily },\n unit: { fontWeight: 400, color: \"#000000\", fontFamily: defaultFontFamily },\n\n \n};\n\n// --- Circuit Breaker Config ---\nconst MAX_FAILURES = 3;\n\n/* ---------------------- Component ---------------------- */\n\nexport const LatestDataGauge: React.FC = ({\n client,\n nodeId,\n variable,\n title = \"Latest Data\",\n min = 0,\n max = 100,\n startAngleDeg = -135, // semi-circle: -90 .. 90\n endAngleDeg = 135,\n thickness, // optional\n zones = defaultZones,\n showNeedle = false,\n needleColor = \"#111\",\n needleWidth = 3,\n subtitle,\n styles = {},\n disabled = false,\n tickCount = 11,\n unit = \"Units\",\n uomOffset = -15,\n labelOffset = -7,\n onMetrics,\n valueText = ({ value: v, valueMin, valueMax }) =>\n v === undefined ? `-- / ${valueMax}` : `${v} / ${valueMax}`,\n onStyleChange,\n displayText,\n}) => {\n\n validateRequiredProps(\n \"LatestDataGauge\",\n { client, nodeId, variable },\n [\"client\", \"nodeId\", \"variable\"]\n );\n \n\n \n const [value,setValue] = useState(null)\n const [node, setNode] = useState(null); // <-- store node in state\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(null);\n\n // Build a state object to pass into the callback styles\nconst widgetState = { value, loading, error };\n\n\n// Resolve function or static style object\nconst [dynamicStyles, setDynamicStyles] = useState>({});\n\nconst baseResolvedStyles =\n typeof styles === \"function\" ? styles(widgetState) : styles || {};\n\nconst resolvedStyles = {\n container: { ...baseResolvedStyles.container, ...dynamicStyles?.container },\n label: { ...baseResolvedStyles.label, ...dynamicStyles?.label },\n value: { ...baseResolvedStyles.value, ...dynamicStyles?.value },\n unit: { ...baseResolvedStyles.unit, ...dynamicStyles?.unit },\n fontFamily: dynamicStyles?.fontFamily ?? baseResolvedStyles.fontFamily,\n subtitle: { ...defaultSubtitleSx, ...baseResolvedStyles.subtitle, ...dynamicStyles.subtitle },\n arc: { ...defaultArcSx, ...baseResolvedStyles.arc, ...dynamicStyles.arc },\n\n};\n // --- Preventing stale closures / infinite renders ---\n \n const isFetchingRef = useRef(false);\n const failureCountRef = useRef(0);\n const mountedRef = useRef(false);\n const svgRef = useRef(null);\n\n // normalize style objects\n const containerSx = normalizeSx(resolvedStyles.container);\n const titleSx = normalizeSx(resolvedStyles.label);\n const valueTextSx = normalizeSx(resolvedStyles.value);\n const subtitleSx = normalizeSx(resolvedStyles.subtitle);\n const unitSx = normalizeSx(resolvedStyles.unit);\n const arcSx = normalizeSx(resolvedStyles.arc);\n\n\n // --- Container dimensions with TypeScript-safe default ---\n const containerDefaults: any = defaultContainerSx!;\n const width = containerSx.width ?? containerDefaults.width;\n const height = containerSx.height ?? containerDefaults.height;\n\n // convert degrees -> radians helper\n const deg2rad = (d: number) => (d * Math.PI) / 180;\n\n // clamp value into min..max safely\n const clamp = (v?: number) =>\n v === undefined ? undefined : Math.max(min, Math.min(max, v));\n\n // derived, memoized (fast)\n const metrics = useMemo(() => {\n const padding = 8; // keep inside svg\n const cx = width / 2;\n const cy = height / 2;\n // Available radius limited by width/height and padding\n const maxRadius = Math.min(width / 2, height / 2) - padding;\n // default thickness if not provided: 20% of radius\n const outerRadius = maxRadius;\n const innerRadius = Math.max(\n 6,\n outerRadius - (thickness ?? Math.round(outerRadius * 0.2))\n );\n // compute value angle\n const startRad = deg2rad(startAngleDeg);\n const endRad = deg2rad(endAngleDeg);\n // clamped value fraction\n const effectiveValue = value === undefined ? undefined : clamp(value);\n const frac =\n effectiveValue === undefined ? 0 : (effectiveValue - min) / (max - min);\n const valueAngleRad = startRad + frac * (endRad - startRad);\n const valueAngleDeg = (valueAngleRad * 180) / Math.PI;\n return {\n maxRadius,\n valueAngleDeg,\n valueAngleRad,\n startAngleDeg,\n endAngleDeg,\n innerRadius,\n outerRadius,\n cx,\n cy,\n } as GaugeMetrics;\n }, [value, min, max, startAngleDeg, endAngleDeg, width, height, thickness]);\n\n useEffect(() => {\n if (client && nodeId) {\n const anedya = (client as any)._anedya as Anedya; // retrieve wrapped instance\n const createdNode = anedya.NewNode(client, nodeId);\n setNode(createdNode);\n }\n}, [client, nodeId]);\n\n\n// --- Fetch data once safely ---\n useEffect(() => {\n\n\n mountedRef.current = true;\n if (!node) return;\n const fetchData= async()=> {\n \n if ( isFetchingRef.current|| failureCountRef.current >= MAX_FAILURES){\n\n //rate limiter ----> in client \n console.log(\"!node:\",node)\n console.log(\"isFetchingRef.current:\",isFetchingRef.current)\n console.log(\"failureCountRef.current:\",failureCountRef.current)\n return\n }; // don't try if node not ready or if an api call is being currently made already\n \n isFetchingRef.current = true;\n try {\n setLoading(true);\n setError(null);\n const res = await node.getLatestData(variable);\n\n if (!mountedRef.current) return; // <-- SAFE, stops state update if unmounted\n\n if (res.isSuccess && res.isDataAvailable) {\n\n setValue(res.data?.value);\n setError(\"\");\n // setValue(null);\n } else {\n setValue(null);\n console.error(\"error fetching data:\", res.error);\n setError(res.error.errorMessage);\n }\n failureCountRef.current = 0; // reset on success\n } catch (err: any) {\n if (!mountedRef.current) return;\n console.error(\"Error fetching latest data:\", err);\n setValue(null);\n setError(err?.message ?? \"Failed to fetch data\");\n failureCountRef.current += 1;\n \n } finally {\n if (!mountedRef.current) return;\n setLoading(false);\n isFetchingRef.current = false;\n }\n }\n fetchData();\n\n return () => {\n mountedRef.current = false;\n };\n \n }, [node, variable]);\n\n // Whenever value changes, allow user to modify styles dynamically\n useEffect(() => {\n if (typeof onStyleChange === \"function\") {\n const updated = onStyleChange(value);\n if (updated && typeof updated === \"object\") {\n setDynamicStyles(updated);\n }\n }\n }, [value]);\nconst formatted: DisplayTextResult = displayText\n ? displayText(Number(value), unit)\n : {\n text: String(value ?? \"\"),\n unitText: unit,\n position: \"right\",\n unitStyle: \"normal\",\n };\n\n\n\n\n\n // call metrics callback if provided\n useEffect(() => {\n if (onMetrics) onMetrics(metrics);\n }, [metrics, onMetrics]);\n\n // D3 draw/cleanup\n useEffect(() => {\n const svg = svgRef.current;\n if (!svg) return;\n\n // clear previous\n d3.select(svg).selectAll(\"*\").remove();\n\n const svgSel = d3.select(svg);\n\n const {\n cx,\n cy,\n outerRadius,\n innerRadius,\n valueAngleRad,\n startAngleDeg: sDeg,\n endAngleDeg: eDeg,\n } = metrics;\n\n // group container for translation and layering\n const g = svgSel.append(\"g\").attr(\"transform\", `translate(${cx}, ${cy})`); // center at 0,0 inside group\n\n // background track -> single full track from startAngle to endAngle (light gray)\n const startRad = deg2rad(sDeg);\n const endRad = deg2rad(eDeg);\n const fullArc = d3\n .arc()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius)\n .startAngle(startRad)\n .endAngle(endRad);\n\n const fullArcPathD = (fullArc as any)(undefined);\n g.append(\"path\")\n .attr(\"d\", fullArcPathD ?? \"\")\n .attr(\"fill\", arcSx.trackColor ?? \"#e6e6e6\")\n .attr(\"stroke\", \"none\");\n\n // draw zones as arcs - zones may exceed min/max so map zone percentages to angles\n // zones are in value units; convert zone from/to -> angles\n const totalAngleSpanRad = deg2rad(eDeg - sDeg);\n\n const valueToAngleRad = (v: number) => {\n const frac = (v - min) / (max - min);\n return startRad + frac * totalAngleSpanRad;\n };\n\n // sanitize zones: sort and clamp to [min, max]\n const safeZones = (zones ?? [])\n .map((z) => ({\n from: Math.max(z.from, min),\n to: Math.min(z.to, max),\n color: z.color,\n }))\n .filter((z) => z.to > z.from)\n .sort((a, b) => a.from - b.from);\n\n safeZones.forEach((z, idx) => {\n const zStart = valueToAngleRad(z.from);\n const zEnd = valueToAngleRad(z.to);\n const arcFn = d3\n .arc()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius)\n .startAngle(zStart)\n .endAngle(zEnd);\n\n const pathD = (arcFn as any)(undefined);\n g.append(\"path\")\n .attr(\"d\", pathD ?? \"\")\n .attr(\"fill\", z.color)\n .attr(\"stroke\", \"none\")\n .attr(\"opacity\", 1);\n });\n\n // Draw progress arc from startRad to valueAngleRad (if value defined)\n if (value !== undefined) {\n // don't draw if value outside range? we clamp earlier to min..max\n const progArc = d3\n .arc()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius)\n .startAngle(startRad)\n .endAngle(valueAngleRad);\n\n const progArcPathD = (progArc as any)(undefined);\n g.append(\"path\")\n .attr(\"d\", progArcPathD ?? \"\")\n .attr(\"fill\", arcSx.progressColor ?? \"rgba(255,255,255,0.15)\")\n .attr(\"stroke\", arcSx.progressStroke ?? \"#00000000\");\n }\n\n // optional needle - pointy line from center to outer radius at valueAngleRad\n if (showNeedle && value !== undefined) {\n const needleLen =\n (innerRadius + outerRadius) / 2 + (outerRadius - innerRadius) * 0.15;\n const needleG = g.append(\"g\").attr(\"class\", \"needle\");\n\n // create triangular needle or line\n const needleLine = d3.line();\n const nx = Math.cos(valueAngleRad - Math.PI / 2) * needleLen;\n const ny = Math.sin(valueAngleRad - Math.PI / 2) * needleLen;\n // Slight rotation because group center at 0,0 and d3 arc angles use 0 at 12 o'clock\n // We'll produce a simple line\n needleG\n .append(\"line\")\n .attr(\"x1\", 0)\n .attr(\"y1\", 0)\n .attr(\"x2\", nx)\n .attr(\"y2\", ny)\n .attr(\"stroke\", needleColor)\n .attr(\"stroke-width\", needleWidth)\n .attr(\"stroke-linecap\", \"round\");\n\n // small center cap\n needleG\n .append(\"circle\")\n .attr(\"cx\", 0)\n .attr(\"cy\", 0)\n .attr(\"r\", Math.max(3, Math.min(6, (outerRadius - innerRadius) * 0.25)))\n .attr(\"fill\", needleColor);\n }\n\n // center value text\n const valueString = valueText({ value, valueMin: min, valueMax: max });\n\n const valueGroup = g.append(\"g\").attr(\"class\", \"value-group\");\n\n valueGroup\n .append(\"text\")\n .attr(\"class\", \"gauge-value-text\")\n .attr(\"text-anchor\", \"middle\")\n .attr(\"y\", -((innerRadius + outerRadius) / 2) * 0.05) // slightly upward\n .style(\n \"font-size\",\n (arcSx.fontSize ?? `${Math.round(innerRadius * 0.45)}px`) as string\n )\n .style(\"font-family\", arcSx.fontFamily ?? \"Roboto, Arial, sans-serif\")\n .style(\"fill\", (valueTextSx.color as any) ?? \"#111\")\n .text(valueString);\n\n // optional subtitle below\n if (subtitle) {\n valueGroup\n .append(\"text\")\n .attr(\"class\", \"gauge-subtitle-text\")\n .attr(\"text-anchor\", \"middle\")\n .attr(\"y\", (outerRadius - innerRadius) * 0.6 + 14)\n .style(\"font-size\", (subtitleSx.fontSize ?? \"12px\") as string)\n .style(\"fill\", subtitleSx.color ?? \"#666\")\n .text(subtitle);\n }\n\n // cleanup on unmount\n return () => {\n d3.select(svg).selectAll(\"*\").remove();\n };\n }, [\n metrics,\n zones,\n value,\n min,\n max,\n showNeedle,\n needleColor,\n needleWidth,\n valueText,\n resolvedStyles, // keep redraw when style shape changes\n ]);\n\n /** Red gradient props for arcSegments */\n const redFade = useGradient(\n \"rgba(255,0,0,0)\",\n \"rgba(255,0,0,1)\",\n \"redFade-randomkey\"\n );\n\n /** Renders coloured arcs to demarcate target ranges. */\n const arcSegments = [\n // {min: 0, max:1, color: \"#148382\"}\n { min: 0, max: 0.5, color: \"rgb(181,230,29)\" },\n { min: 0.5, max: 1, color: \"orange\" },\n {\n min: 0.75,\n max: 1,\n ...redFade,\n },\n ];\n\n // --- Scaled font sizes ---\n const baseFont = Math.min(Number(width), Number(height)) * 0.15;\n\n // --- Compute font sizes dynamically if not provided by user ---\n const labelFont = (resolvedStyles?.label as any)?.fontSize ?? baseFont * 0.6;\n\n const valueFont = (resolvedStyles?.value as any)?.fontSize ?? baseFont * 1.2;\n\n const unitFont = (resolvedStyles?.unit as any)?.fontSize ?? baseFont * 0.8;\n\n // overall container style (MUI Box)\n const mergedContainer = {\n ...defaultContainerSx,\n ...containerSx,\n width,\n height,\n \n };\n // --- Font family handling ---\n const globalFontFamily = resolvedStyles?.fontFamily ?? \"Roboto\";\n const labelFontFamily = defaultContainerSx.label?.fontFamily ?? globalFontFamily;\n const valueFontFamily = defaultContainerSx.value?.fontFamily ?? globalFontFamily;\n const unitFontFamily = defaultContainerSx.label?.fontFamily ?? globalFontFamily;\n \n\n const mergedLabelSx: CSSProperties = {\n ...defaultContainerSx.label,\n fontSize: labelFont,\n ...titleSx,\n fontFamily: labelFontFamily,\n };\n const mergedValueSx: CSSProperties = {\n ...defaultContainerSx.value,\n fontSize: valueFont,\n // color: textColor,\n ...valueTextSx,\n fontFamily: valueFontFamily,\n };\n const mergedUnitSx: CSSProperties = {\n ...defaultContainerSx.unit,\n fontSize: unitFont,\n ...unitSx,\n fontFamily: unitFontFamily,\n };\n \n\n return (\n \n
\n {title && (\n

\n {title}\n

\n )}\n {loading ? (\n \n
\n \n ) : error ? (\n \n
\n \n{error}\n
\n\n \n \n \n ) : value ? (\n \n ): !value?\n \n\n
\n \n{ \"No data available\"}\n
\n\n \n\n :<>}\n \n \n );\n};\n\nexport default LatestDataGauge;\n","import React from \"react\";\nimport { Gradient } from \"../components\";\n\nconst useGradient = (startColour:string, stopColour:string, id:string) => {\n return {\n color: `url(#${id})`,\n // node: disabled => (\n // \n // )\n };\n};\n\nexport default useGradient;\n"],"names":["extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","prototype","hasOwnProperty","call","__extends","TypeError","String","__","this","constructor","create","__assign","assign","t","s","i","n","arguments","length","apply","__rest","e","indexOf","getOwnPropertySymbols","propertyIsEnumerable","__awaiter","thisArg","_arguments","P","generator","Promise","resolve","reject","fulfilled","value","step","next","rejected","result","done","then","__generator","body","f","y","_","label","sent","trys","ops","g","Iterator","verb","Symbol","iterator","v","op","pop","push","__spreadArray","to","from","pack","ar","l","slice","concat","SuppressedError","u","R","tokenId","token","baseUrl","trim","Error","D","tokenBytes","signatureVersionBytes","signatureVersion","authorizationMode","a","TextEncoder","encode","isSuccess","error","isDataAvailable","data","count","startTime","endTime","errorMessage","reasonCode","h","namespace","key","type","size","modified","created","scope","id","A","I","totalCount","S","m","async","o","JSON","stringify","c","crypto","subtle","digest","Uint8Array","DataView","buffer","setBigUint64","BigInt","set","map","toString","padStart","join","console","log","w","r","getNodeId","getData","nodes","variable","Math","floor","limit","order","Date","now","Authorization","fetch","method","credentials","headers","json","success","keys","status","statusText","G","getLatestData","k","setKey","V","getKey","O","deleteKey","q","scanKeys","filter","orderby","offset","M","getDeviceStatus","lastContactThreshold","U","getSnapshot","time","node","E","NewConfig","NewClient","NewNode","B","GLOBAL","NODE","X","STRING","BINARY","FLOAT","BOOLEAN","globalClient","nodeRateLimiters","Map","anedyaClientInit","options","_this","useGlobal","_a","forceReinit","_b","rateLimitMs","_c","anedya","Anedya","config","client","originalNewNode","bind","args","_i","nodeId","limiter","get","lastCallTime","interval","originalGetLatestData_1","params","elapsed","wait_1","warn","setTimeout","err_1","_anedya","validateRequiredProps","componentName","props","required","missing","undefined","message","defaultColorRanges","max","color","Infinity","defaultFontFamily","defaultStyles","container","width","height","padding","margin","display","flexDirection","justifyContent","alignItems","borderRadius","boxSizing","background","border","fontFamily","gap","textAlign","fontWeight","unit","normalizeSx","sx","isArray","LatestDataWidgetComponent","_t","title","_u","_v","styles","displayText","colorRange","colorRangeCallback","onStyleChange","_w","useState","setData","_x","loading","setLoading","_y","setError","_z","setNode","isFetchingRef","useRef","failureCountRef","mountedRef","widgetState","_0","dynamicStyles","setDynamicStyles","baseResolvedStyles","resolvedStyles","formatted","Number","text","unitText","position","unitStyle","useEffect","createdNode","current","res","updated","containerSx","labelSx","valueSx","unitSx","containerDefaults","_d","baseFont","min","labelFont","_f","_e","fontSize","valueFont","_h","_g","unitFont","_k","_j","globalFontFamily","_l","labelFontFamily","_m","valueFontFamily","_o","unitFontFamily","_p","containerGap","_q","finalRange","textColor","ranges","range","find","getColorFromRange","_r","_s","mergedContainerSx","mergedLabelSx","mergedValueSx","mergedUnitSx","renderUnitText","style","_jsx","children","_jsxs","className","paddingRight","paddingLeft","boxShadow","_Fragment","LatestDataWidget","React","memo","prev","ascending","NaN","descending","bisector","compare1","compare2","delta","left","x","lo","hi","mid","zero","center","right","bisectRight","e10","sqrt","e5","e2","tickSpec","start","stop","power","log10","pow","factor","i1","i2","inc","round","tickIncrement","tickStep","reverse","identity$3","epsilon","translateX","translateY","number","scale","bandwidth","entering","__axis","axis","orient","tickArguments","tickValues","tickFormat","tickSizeInner","tickSizeOuter","tickPadding","window","devicePixelRatio","transform","context","values","ticks","domain","format","identity","spacing","range0","range1","copy","selection","path","selectAll","tick","tickExit","exit","tickEnter","enter","append","attr","line","select","merge","insert","transition","isFinite","getAttribute","parentNode","remove","each","tickSize","noop","dispatch","test","Dispatch","name","callback","on","typename","types","T","split","that","xhtml","namespaces","svg","xlink","xml","xmlns","prefix","space","local","creatorInherit","document","ownerDocument","uri","namespaceURI","documentElement","createElement","createElementNS","creatorFixed","fullname","creator","none","selector","querySelector","empty","selectorAll","querySelectorAll","arrayAll","array","matcher","matches","childMatcher","childFirst","firstElementChild","sparse","update","EnterNode","parent","datum","_next","_parent","__data__","bindIndex","group","groupLength","dataLength","bindKey","keyValue","nodeByKeyValue","keyValues","has","delete","arraylike","attrRemove","removeAttribute","attrRemoveNS","removeAttributeNS","attrConstant","setAttribute","attrConstantNS","setAttributeNS","attrFunction","attrFunctionNS","defaultView","styleRemove","removeProperty","styleConstant","priority","setProperty","styleFunction","styleValue","getPropertyValue","getComputedStyle","propertyRemove","propertyConstant","propertyFunction","classArray","string","classList","ClassList","_node","_names","classedAdd","names","list","add","classedRemove","classedTrue","classedFalse","classedFunction","textRemove","textContent","textConstant","textFunction","htmlRemove","innerHTML","htmlConstant","htmlFunction","raise","nextSibling","appendChild","lower","previousSibling","insertBefore","firstChild","constantNull","removeChild","selection_cloneShallow","clone","cloneNode","selection_cloneDeep","onRemove","__on","j","removeEventListener","listener","onAdd","event","contextListener","addEventListener","dispatchEvent","CustomEvent","createEvent","initEvent","bubbles","cancelable","detail","dispatchConstant","dispatchFunction","child","splice","contains","root","Selection","groups","parents","_groups","_parents","define","factory","extend","definition","Color","subgroups","subnode","subgroup","selectChild","match","childFind","selectChildren","childrenFilter","constant","enterGroup","updateGroup","previous","i0","_enter","_exit","onenter","onupdate","onexit","groups0","groups1","m0","m1","merges","group0","group1","compareDocumentPosition","sort","compare","compareNode","sortgroups","sortgroup","getAttributeNS","property","classed","html","before","deep","typenames","parseTypenames","darker","brighter","reI","reN","reP","reHex","reRgbInteger","RegExp","reRgbPercent","reRgbaInteger","reRgbaPercent","reHslPercent","reHslaPercent","named","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","green","greenyellow","grey","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen","color_formatHex","rgb","formatHex","color_formatRgb","formatRgb","toLowerCase","exec","parseInt","rgbn","Rgb","rgba","hsla","opacity","rgb_formatHex","hex","rgb_formatRgb","clampa","clampi","isNaN","Hsl","hslConvert","clamph","clampt","hsl2rgb","m2","channels","displayable","formatHex8","formatHsl","clamp","constant$1","gamma","nogamma","exponential","linear","interpolateRgb","rgbGamma","end","colorRgb","numberArray","genericArray","nb","na","date$1","setTime","interpolateNumber","object","reA","reB","source","interpolateString","am","bm","bs","bi","lastIndex","index","one","interpolate$1","date","ArrayBuffer","isView","isNumberArray","valueOf","interpolateRound","svgNode","degrees","PI","rotate","skewX","scaleX","scaleY","decompose","atan2","atan","interpolateTransform","parse","pxComma","pxParen","degParen","xa","ya","xb","yb","translate","taskHead","taskTail","interpolateTransformCss","DOMMatrix","WebKitCSSMatrix","isIdentity","interpolateTransformSvg","baseVal","consolidate","matrix","frame","timeout","clockLast","clockNow","clockSkew","clock","performance","setFrame","requestAnimationFrame","clearNow","Timer","_call","_time","timer","delay","restart","wake","timerFlush","t0","t2","t1","sleep","nap","poke","clearTimeout","clearInterval","setInterval","emptyOn","emptyTween","schedule","timing","schedules","__transition","self","tween","state","duration","ease","init","tweenRemove","tween0","tween1","tweenFunction","tweenValue","_id","interpolate","value1","string00","interpolate0","string1","string0","string10","attrTweenNS","attrInterpolateNS","_value","attrTween","attrInterpolate","delayFunction","delayConstant","durationFunction","durationConstant","Transition","_name","newId","selection_prototype","inherit","id0","id1","on0","on1","sit","every","onFunction","styleTween","styleNull","listener0","styleMaybeRemove","styleInterpolate","textTween","textInterpolate","removeFunction","easeConstant","easeVarying","cancel","interrupt","defaultTiming","active","pi","tau","tauEpsilon","strings","Path","digits","_x0","_y0","_x1","_y1","_append","appendRound","moveTo","closePath","lineTo","quadraticCurveTo","x1","y1","bezierCurveTo","x2","y2","arcTo","x0","y0","x21","y21","x01","y01","l01_2","abs","x20","y20","l21_2","l20_2","l21","l01","acos","t01","t21","arc","a0","a1","ccw","dx","cos","dy","sin","cw","da","rect","formatDecimalParts","toExponential","coefficient","exponent","prefixExponent","re","formatSpecifier","specifier","FormatSpecifier","fill","align","sign","symbol","comma","precision","formatRounded","formatTypes","toFixed","toLocaleString","replace","toPrecision","toUpperCase","identity$1","locale","formatPrefix","prefixes","formatLocale$1","grouping","thousands","substring","currencyPrefix","currency","currencySuffix","decimal","numerals","formatNumerals","percent","minus","nan","newFormat","suffix","formatType","maybeSuffix","valuePrefix","valueSuffix","valueNegative","out","formatTrim","charCodeAt","initRange","formatLocale","normalize","bimap","d0","d1","r0","r1","polymap","bisect","target","unknown","transformer","untransform","piecewise","output","input","interpolateValue","rescale","clamper","invert","rangeRound","continuous","precisionPrefix","precisionRound","precisionFixed","linearish","nice","prestep","maxIter","ceil","timeInterval","floori","offseti","field","millisecond","durationSecond","durationMinute","durationHour","durationDay","durationWeek","durationMonth","durationYear","second","getMilliseconds","getUTCSeconds","timeMinute","getSeconds","getMinutes","utcMinute","setUTCSeconds","getUTCMinutes","timeHour","getHours","utcHour","setUTCMinutes","getUTCHours","timeDay","setHours","setDate","getDate","getTimezoneOffset","utcDay","setUTCHours","setUTCDate","getUTCDate","unixDay","timeWeekday","getDay","timeSunday","timeMonday","timeTuesday","timeWednesday","timeThursday","timeFriday","timeSaturday","utcWeekday","getUTCDay","utcSunday","utcMonday","utcTuesday","utcWednesday","utcThursday","utcFriday","utcSaturday","timeMonth","setMonth","getMonth","getFullYear","utcMonth","setUTCMonth","getUTCMonth","getUTCFullYear","timeYear","setFullYear","utcYear","setUTCFullYear","timeTicks","timeTickInterval","year","month","week","day","hour","minute","tickIntervals","tickInterval","ticker","localDate","H","L","utcDate","UTC","newDate","timeFormat","pads","numberRe","percentRe","requoteRe","pad","requote","formatRe","formatLookup","parseWeekdayNumberSunday","parseWeekdayNumberMonday","parseWeekNumberSunday","parseWeekNumberISO","parseWeekNumberMonday","W","parseFullYear","parseYear","parseZone","Z","parseQuarter","parseMonthNumber","parseDayOfMonth","parseDayOfYear","parseHour24","parseMinutes","parseSeconds","parseMilliseconds","parseMicroseconds","parseLiteralPercent","parseUnixTimestamp","Q","parseUnixTimestampSeconds","formatDayOfMonth","formatHour24","formatHour12","formatDayOfYear","formatMilliseconds","formatMicroseconds","formatMonthNumber","formatMinutes","formatSeconds","formatWeekdayNumberMonday","formatWeekNumberSunday","dISO","formatWeekNumberISO","formatWeekdayNumberSunday","formatWeekNumberMonday","formatYear","formatYearISO","formatFullYear","formatFullYearISO","formatZone","z","formatUTCDayOfMonth","formatUTCHour24","formatUTCHour12","formatUTCDayOfYear","formatUTCMilliseconds","getUTCMilliseconds","formatUTCMicroseconds","formatUTCMonthNumber","formatUTCMinutes","formatUTCSeconds","formatUTCWeekdayNumberMonday","dow","formatUTCWeekNumberSunday","UTCdISO","formatUTCWeekNumberISO","formatUTCWeekdayNumberSunday","formatUTCWeekNumberMonday","formatUTCYear","formatUTCYearISO","formatUTCFullYear","formatUTCFullYearISO","formatUTCZone","formatLiteralPercent","formatUnixTimestamp","formatUnixTimestampSeconds","calendar","formatMillisecond","formatSecond","formatMinute","formatHour","formatDay","formatWeek","formatMonth","timeWeek","timeSecond","locale_dateTime","dateTime","locale_date","locale_time","locale_periods","periods","locale_weekdays","days","locale_shortWeekdays","shortDays","locale_months","months","locale_shortMonths","shortMonths","periodRe","periodLookup","weekdayRe","weekdayLookup","shortWeekdayRe","shortWeekdayLookup","monthRe","monthLookup","shortMonthRe","shortMonthLookup","formats","Y","utcFormats","parses","parseSpecifier","charAt","newParse","utcFormat","utcParse","defaultLocale","halfPi","asin","withPath","shape","RangeError","arcInnerRadius","innerRadius","arcOuterRadius","outerRadius","arcStartAngle","startAngle","arcEndAngle","endAngle","arcPadAngle","padAngle","cornerTangents","rc","ox","oy","x11","y11","x10","y10","x00","y00","d2","cx0","cy0","cx1","cy1","dx0","dy0","dx1","dy1","cx","cy","cornerRadius","padRadius","a01","a11","a00","a10","da0","da1","ap","rp","rc0","rc1","p0","p1","oc","x3","y3","x32","y32","intersect","ax","ay","bx","by","kc","lc","centroid","Linear","_context","curveLinear","defined","curve","defined0","lineStart","lineEnd","point","pointX","pointY","area","x0z","y0z","areaStart","areaEnd","arealine","lineX0","lineY0","lineY1","lineX1","_line","_point","curveRadialLinear","curveRadial","Radial","_curve","radial","lineRadial$1","angle","radius","circle","draw","sqrt3","symbolTriangle","slope3","h0","h1","s0","s1","slope2","MonotoneX","monotoneX","Transform","_t0","applyX","applyY","location","invertX","invertY","rescaleX","rescaleY","formatDate","css","ref","insertAt","head","getElementsByTagName","styleSheet","cssText","createTextNode","toDateSafe","ts","tooltip","chart","strokeColor","strokeWidth","gradientColors","dotRadius","ChartWidget","tooltipFormatter","timestamp","hour12","tickCount","tickFormatter","xTickFormat","yTickFormat","tooltipFormat","resolvedXFormatter","resolvedYFormatter","decimals","includes","formatNumber","resolvedTooltipFormatter","svgRef","tooltipNodeRef","titleSx","tooltipSx","chartSx","axisSx","req","d3.select","chartW","chartH","dates","d3.scaleTime","d3.extent","maxY","valueof","d3.max","d3.scaleLinear","safeGradient","safeStroke","safeWidth","safeDotRadius","gradient","d3\n .area","d3.curveMonotoneX","d3\n .line","dotR","requested","base","computeDotRadius","dots","tooltipDiv","tooltipDefaults","pointerEvents","backgroundColor","innerWidth","pageX","top","pageY","xAxis","Intl","DateTimeFormat","defaultDateFormatter","axisDefaults","d3.axisLeft","clipId","random","SVGBase","_super","render","PureComponent","Pointer","tail","minAngle","maxAngle","disabled","pointerLine","pointerValue","scaleLinear","valueScale","moveTooltip","getElementById","clientX","clientY","onMouseEnter","showTooltip","onMouseMove","onMouseLeave","InvertedTriangle","stroke","UnitOfMeasurement","offsetText","uom","GaugeArc","inset","maxRatio","arcMax","minRatio","arcMin","refToRads","arcScale","arcPath","lineRadial","tickLineLong","tickLineShort","Label","minVal","maxVal","idxToRef","idxToVal","refToDeg","val","deg","getTickRef","userSelect","Gradient","stopColor","Gauge","arcSegments","labelProps","uomProps","pointerLabel","gaugeOrigin","useCallback","valueRef","useMemo","viewBox","idx","defaultArcSx","trackColor","progressColor","progressStroke","defaultSubtitleSx","defaultZones","defaultContainerSx","overflowWrap","LatestDataGauge","startAngleDeg","endAngleDeg","thickness","zones","showNeedle","needleColor","_1","needleWidth","subtitle","_2","_3","_4","_5","_6","uomOffset","_7","labelOffset","onMetrics","_8","valueText","valueMin","valueMax","_9","setValue","_10","_11","_12","_13","valueTextSx","subtitleSx","arcSx","deg2rad","metrics","maxRadius","startRad","endRad","effectiveValue","valueAngleRad","valueAngleDeg","svgSel","sDeg","eDeg","fullArcPathD","d3\n .arc","fullArc","totalAngleSpanRad","valueToAngleRad","safeZones","forEach","zStart","zEnd","pathD","d3\n .arc","arcFn","progArcPathD","progArc","needleLen","needleG","d3.line","nx","ny","valueString","valueGroup","redFade","startColour","stopColour","useGradient","mergedContainer"],"mappings":"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","x_google_ignoreList":[0,1,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,161,163,164]} \ No newline at end of file diff --git a/dist/style.css b/dist/style.css index 9097ed1f..4fea5a80 100644 --- a/dist/style.css +++ b/dist/style.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-blue-500:oklch(62.3% .214 259.815);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-normal:400;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.ml-1{margin-left:var(--spacing)}.contents{display:contents}.flex{display:flex}.inline{display:inline}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.gap-1{gap:var(--spacing)}.rounded{border-radius:.25rem}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-4{padding:calc(var(--spacing) * 4)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.5em\]{font-size:.5em}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-blue-500{color:var(--color-blue-500)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/dist/styles.css b/dist/styles.css deleted file mode 100644 index 81d7b699..00000000 --- a/dist/styles.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.rounded{border-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.invert{--tw-invert:invert(100%);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 21f1137c..22e7fccb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,7 @@ "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", "tsup": "^8.5.1", - "typescript": "^7.0.2" + "typescript": "^5.7.3" }, "peerDependencies": { "@base-ui/react": "^1.0.0", @@ -1936,346 +1936,6 @@ "csstype": "^3.2.2" } }, - "node_modules/@typescript/typescript-aix-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", - "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-darwin-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", - "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-darwin-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", - "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-freebsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", - "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-freebsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", - "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-arm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", - "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", - "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-loong64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", - "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-mips64el": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", - "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", - "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-riscv64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", - "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-s390x": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", - "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-linux-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", - "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-netbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", - "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-netbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", - "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-openbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", - "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-openbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", - "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-sunos-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", - "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-win32-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", - "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/@typescript/typescript-win32-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", - "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } - }, "node_modules/acorn": { "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", @@ -3915,38 +3575,17 @@ } }, "node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc" + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=16.20.0" - }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" + "node": ">=14.17" } }, "node_modules/ufo": { diff --git a/package.json b/package.json index 5b92d537..e3ade950 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "./styles.css": "./dist/styles.css" }, "scripts": { - "build:css": "tailwindcss -i src/styles.css -o dist/styles.css --minify", - "build:js": "tsup", - "build": "npm run build:css && npm run build:js", + "clean": "rm -rf dist", + "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify", + "build:js": "tsup", + "build": "npm run clean && npm run build:js && npm run build:css", "typecheck": "tsc --noEmit" }, "repository": { @@ -48,6 +49,6 @@ "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", "tsup": "^8.5.1", - "typescript": "^7.0.2" + "typescript": "^5.7.3" } } diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 67a50cb0..276c9a29 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -257,7 +257,7 @@ export function CardWidget({ {error} ) : ( <> - + {/* {displayValue} {resolvedProps.unit && ( )} - + */} + + {displayValue} + + {resolvedProps.unit && ( + + {resolvedProps.unit} + + )} + {displayLabel && ( + {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same diff --git a/test/my-app/vite.config.js b/test/my-app/vite.config.js index 19471f13..6ad23181 100644 --- a/test/my-app/vite.config.js +++ b/test/my-app/vite.config.js @@ -13,3 +13,4 @@ export default defineConfig({ }, }) + diff --git a/tsup.config.ts b/tsup.config.ts index 817804f4..42f9e6ce 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -4,6 +4,7 @@ export default defineConfig({ entry: ["src/index.ts"], format: ["esm", "cjs"], dts: true, + tsconfig: "./ts.config.json", external: ["react", "react-dom", "@base-ui/react"], - clean: true, + clean: false, }); \ No newline at end of file From dd8faf41deafc8556364d48e724e96a9c88ef3a5 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Thu, 23 Jul 2026 13:23:26 +0530 Subject: [PATCH 22/66] commit --- dist/index.d.mts | 122 ---- dist/index.d.ts | 122 ---- dist/style.css | 2 - package-lock.json | 20 +- .../GaugeChart/GaugeChartWidget.tsx | 664 ++++++++++++++++++ src/hooks/useResizeObserver.ts | 36 + src/styles/base.css | 65 ++ src/themes/gaugeTheme.ts | 63 ++ test/my-app/src/App.jsx | 71 +- 9 files changed, 897 insertions(+), 268 deletions(-) delete mode 100644 dist/index.d.mts delete mode 100644 dist/index.d.ts delete mode 100644 dist/style.css create mode 100644 src/components/GaugeChart/GaugeChartWidget.tsx create mode 100644 src/hooks/useResizeObserver.ts create mode 100644 src/themes/gaugeTheme.ts diff --git a/dist/index.d.mts b/dist/index.d.mts deleted file mode 100644 index 37d78af8..00000000 --- a/dist/index.d.mts +++ /dev/null @@ -1,122 +0,0 @@ -import * as react_jsx_runtime from 'react/jsx-runtime'; - -type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; -type BuiltInTheme = "light" | "dark"; - -/** - * Generic per-slot class overrides. Every widget defines its own slot - * names (Card: container/title/value/unit/label, Chart: container/line/ - * axis/...) but they all share this same shape. - */ -type SlotClassNames = Partial>; -/** - * A widget theme is simply a reusable collection of Tailwind (or plain - * CSS) classes for a widget's slots. - * - * Themes are merged in three layers: - * - * built-in theme - * ↓ - * user theme - * ↓ - * widget classNames prop - * - * Later layers win via `twMerge`. - */ -interface WidgetTheme { - classNames: SlotClassNames; -} - -/** - * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this - * rather than repeating client/node/sizing/theme plumbing per widget. - * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. - */ -interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; -} - -type CardSlot = "container" | "title" | "value" | "unit" | "label"; -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -interface CardData { - value: number; - timestamp: number; -} -type CardWidgetUpdate = Partial>; -interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - classNames?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * classNames: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; -} -declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react_jsx_runtime.JSX.Element; - -export { CardWidget }; diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index 37d78af8..00000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as react_jsx_runtime from 'react/jsx-runtime'; - -type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; -type BuiltInTheme = "light" | "dark"; - -/** - * Generic per-slot class overrides. Every widget defines its own slot - * names (Card: container/title/value/unit/label, Chart: container/line/ - * axis/...) but they all share this same shape. - */ -type SlotClassNames = Partial>; -/** - * A widget theme is simply a reusable collection of Tailwind (or plain - * CSS) classes for a widget's slots. - * - * Themes are merged in three layers: - * - * built-in theme - * ↓ - * user theme - * ↓ - * widget classNames prop - * - * Later layers win via `twMerge`. - */ -interface WidgetTheme { - classNames: SlotClassNames; -} - -/** - * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this - * rather than repeating client/node/sizing/theme plumbing per widget. - * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. - */ -interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; -} - -type CardSlot = "container" | "title" | "value" | "unit" | "label"; -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -interface CardData { - value: number; - timestamp: number; -} -type CardWidgetUpdate = Partial>; -interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - classNames?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * classNames: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; -} -declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react_jsx_runtime.JSX.Element; - -export { CardWidget }; diff --git a/dist/style.css b/dist/style.css deleted file mode 100644 index 4fea5a80..00000000 --- a/dist/style.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 788bb917..74038084 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1924,18 +1924,6 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, "node_modules/acorn": { "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", @@ -2077,6 +2065,14 @@ "node": "^14.18.0 || >=16.10.0" } }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/d3": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx new file mode 100644 index 00000000..6aa8f4da --- /dev/null +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -0,0 +1,664 @@ +import { useEffect, useMemo, useRef, useState } from "react"; +import { twMerge } from "tailwind-merge"; +import * as d3 from "d3"; +import {SlotClassNames, WidgetTheme } from "../../types/root"; +import { AnedyaWidgetBaseProps } from "../../common"; +import { + GAUGE_DEFAULT_CLASSES, + gaugeThemes, + GaugeSlot, +} from "../../themes/gaugeTheme"; +import { useResizeObserver } from "../../hooks/useResizeObserver"; + +export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { + variant?: "progress" | "needle" | "segmented" | "multiBar"; + value?: number; + + min?: number; + max?: number; + size?: number; + + arc?: { + startAngle?: number; // degrees, default 180 + endAngle?: number; // degrees, default 0 (semi-circle left to right) + thickness?: number; + cornerRadius?: number; + gap?: number; + }; + + track?: { + show?: boolean; + color?: string; + }; + + fillMode?: "progress" | "solid"; + + bars?: Array<{ + value: number; + color?: string; + label?: string; + }>; + + needle?: { + show?: boolean; + type?: "line" | "rounded" | "drop" | "triangle"; + length?: "short" | "medium" | "full" | number; + width?: number; + color?: string; + capRadius?: number; + animation?: boolean; + }; + + valueLabel?: { + show?: boolean; + precision?: number; + prefix?: string; + suffix?: string; + formatter?: (value: number) => string; + }; + + needleLabel?: { + show?: boolean; + formatter?: (value: number) => string; + }; + + scale?: { + minLabel?: string; + maxLabel?: string; + }; + + ticks?: { + show?: boolean; + count?: number; + position?: "inside" | "outside" | "cross"; + length?: number; + labels?: boolean; + }; + + segments?: Array<{ + from: number; + to: number; + color: string; + }>; + + thresholds?: Array<{ + value: number; + color: string; + }>; + + gradient?: { + colors: string[]; + }; + + animation?: { + duration?: number; + easing?: string; + }; + + tooltip?: { + show?: boolean; + }; + + onClick?: () => void; + onHover?: (isHover: boolean) => void; + onValueChange?: (value: number) => void; + + classNames?: SlotClassNames; +} + +// Helper: convert degrees to radians +const deg2rad = (deg: number) => (deg * Math.PI) / 180; + +// Default angles for semi-circle (left to right) +const DEFAULT_START_ANGLE = 180; +const DEFAULT_END_ANGLE = 0; + +export function GaugeWidget({ + node, + variable, + value: valueOverride, + title, + variant = "progress", + min = 0, + max = 100, + size, + arc: arcProps = {}, + track: trackProps = {}, + fillMode = "progress", + bars, + needle: needleProps = {}, + valueLabel: valueLabelProps = {}, + needleLabel: needleLabelProps = {}, + scale: scaleProps = {}, + ticks: ticksProps = {}, + segments, + thresholds, + gradient, + animation, + tooltip, + onClick, + onHover, + onValueChange, + classNames = {}, + theme, + className, + width: initialWidth, + height: initialHeight, + minWidth, + maxWidth, +}: GaugeWidgetProps) { + const containerRef = useRef(null); + const svgRef = useRef(null); + + // ----- Data fetching (same as CardWidget) ----- + const [fetchedValue, setFetchedValue] = useState(null); + const [fetchedTimestamp, setFetchedTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const mountedRef = useRef(false); + + useEffect(() => { + if (!node) return; + mountedRef.current = true; + const fetchLatest = async () => { + setLoading(true); + setError(null); + try { + const res = await node.getLatestData(variable); + if (!mountedRef.current) return; + if (res.isSuccess && res.isDataAvailable) { + setFetchedValue(res.data.value); + setFetchedTimestamp(res.data.timestamp); + } else { + setFetchedValue(null); + setError(res.error?.errorMessage ?? "No data available"); + } + } catch (err: any) { + if (!mountedRef.current) return; + setFetchedValue(null); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + } + } + }; + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + + // Resolve displayed value + const value = valueOverride ?? fetchedValue; + + // ----- Dynamic overrides (like onDataChange in Card) ----- + const [dynamicProps, setDynamicProps] = useState>({}); + useEffect(() => { + if (onValueChange) { + onValueChange(value ?? 0); + } + }, [value, onValueChange]); + + // We can support an onDataChange like callback if desired; for now keep simple + + // Merge all props (original + dynamic) + const resolvedProps = { + ...({ + variant, + min, + max, + arc: arcProps, + track: trackProps, + fillMode, + bars, + needle: needleProps, + valueLabel: valueLabelProps, + needleLabel: needleLabelProps, + scale: scaleProps, + ticks: ticksProps, + segments, + thresholds, + gradient, + animation, + tooltip, + } as GaugeWidgetProps), + ...dynamicProps, + classNames: { + ...classNames, + ...(dynamicProps.classNames ?? {}), + }, + }; + + // Resolve theme + const resolvedTheme: WidgetTheme = + theme === "dark" + ? gaugeThemes.dark + : theme === "light" + ? gaugeThemes.light + : (theme as WidgetTheme) ?? gaugeThemes.light; + + // Slot resolution (lowest to highest precedence) + const resolveSlot = (slot: GaugeSlot) => + twMerge( + GAUGE_DEFAULT_CLASSES[slot], + resolvedTheme.classNames[slot], + resolvedProps.classNames?.[slot], + ); + + // ----- Resize observer for dynamic SVG size ----- + const { ref: gaugeContainerRef, width: containerWidth, height: containerHeight } = + useResizeObserver(); + + // Combine refs: containerRef for our own use, resizeRef for observer + const setContainerRef = (node: HTMLDivElement | null) => { + containerRef.current = node; + (resizeRef as any)(node); + }; + + // Final dimensions (shorthand size overrides width/height) + const effectiveWidth = size ?? initialWidth ?? containerWidth; + const effectiveHeight = size ?? initialHeight ?? containerHeight; + + // ----- Arc configuration ----- + const startAngleDeg = arcProps.startAngle ?? DEFAULT_START_ANGLE; + const endAngleDeg = arcProps.endAngle ?? DEFAULT_END_ANGLE; + const thickness = arcProps.thickness ?? 12; + const cornerRadius = arcProps.cornerRadius ?? 0; + const gap = arcProps.gap ?? 2; + + // Convert to radians for D3 + const startAngleRad = deg2rad(startAngleDeg); + const endAngleRad = deg2rad(endAngleDeg); + + // Compute angle for a given value + const valueToAngle = (val: number) => { + const clamped = Math.min(max, Math.max(min, val)); + const ratio = (clamped - min) / (max - min); + return startAngleRad + ratio * (endAngleRad - startAngleRad); + }; + + // D3 arc generator + const createArc = (innerRadius: number, outerRadius: number) => + d3.arc() + .innerRadius(innerRadius) + .outerRadius(outerRadius) + .startAngle(startAngleRad) + .endAngle(endAngleRad) + .cornerRadius(cornerRadius); + + // ----- SVG drawing ----- + useEffect(() => { + if (!svgRef.current || !containerRef.current) return; + + const svg = d3.select(svgRef.current); + svg.selectAll("*").remove(); // clear previous render + + const w = effectiveWidth; + const h = effectiveHeight; + const cx = w / 2; + const cy = h / 2; + + // Determine arc radii based on available space and thickness + const maxRadius = Math.min(cx, cy) - 10; // padding + const outerRadius = maxRadius; + const innerRadius = outerRadius - thickness; + + // Helper to draw an arc (for track, bar, segments) + const drawArc = ( + selection: d3.Selection, + startAngle: number, + endAngle: number, + innerR: number, + outerR: number, + className?: string, + ) => { + const arcGen = d3.arc() + .innerRadius(innerR) + .outerRadius(outerR) + .startAngle(startAngle) + .endAngle(endAngle) + .cornerRadius(cornerRadius); + selection.attr("d", arcGen as any); + if (className) selection.attr("class", className); + }; + + // ----- Track ----- + if (trackProps.show !== false) { + const trackArc = createArc(innerRadius, outerRadius); + svg.append("path") + .datum({ endAngle: endAngleRad }) + .attr("d", trackArc as any) + .attr("class", resolveSlot("track")) + .attr("fill", "none") + .attr("stroke-width", thickness); + } + + // ----- Determine bar fill color (from thresholds or single color) ----- + let barColorClass = ""; // we use Tailwind classes for dynamic color via CSS variables? We'll rely on the slot class. + // For simplicity, we let the slot "bar" carry the default stroke color via CSS variable. + // Segments and thresholds add their own inline styles if needed. + // We'll apply colors directly via inline style when needed. + + // ----- Variant: progress bar (single arc) ----- + if (variant === "progress" || variant === "needle" || variant === "segmented") { + const currentAngle = valueToAngle(value ?? min); + const progressArc = d3.arc() + .innerRadius(innerRadius) + .outerRadius(outerRadius) + .startAngle(startAngleRad) + .endAngle(currentAngle) + .cornerRadius(cornerRadius); + + // Handle segments + if (segments && segments.length > 0) { + // Draw segments as separate colored arcs spanning the full range + segments.forEach((seg) => { + const segStart = valueToAngle(seg.from); + const segEnd = valueToAngle(seg.to); + svg.append("path") + .datum({ endAngle: segEnd }) + .attr("d", (d) => { + const arc = d3.arc() + .innerRadius(innerRadius) + .outerRadius(outerRadius) + .startAngle(segStart) + .endAngle(d.endAngle) + .cornerRadius(0); + return arc(d); + }) + .attr("fill", "none") + .attr("stroke", seg.color) + .attr("stroke-width", thickness) + .attr("class", resolveSlot("segment")); + }); + + // If fillMode is progress, we overlay the bar only up to current value using a clip-path? + // We'll just draw the bar on top. + if (fillMode === "progress") { + svg.append("path") + .attr("d", progressArc as any) + .attr("fill", "none") + .attr("stroke", "currentColor") // will be overridden by class + .attr("stroke-width", thickness) + .attr("class", resolveSlot("bar")); + } + } else { + // Standard bar (no segments) + // If thresholds exist, choose color based on current value + let strokeColor = ""; + if (thresholds && thresholds.length > 0) { + const threshold = [...thresholds] + .sort((a, b) => a.value - b.value) + .find(t => (value ?? min) <= t.value) ?? thresholds[thresholds.length - 1]; + strokeColor = threshold.color; + } + + if (fillMode === "solid") { + // Draw a full arc as the bar, with solid color + const fullArc = createArc(innerRadius, outerRadius); + svg.append("path") + .datum({ endAngle: endAngleRad }) + .attr("d", fullArc as any) + .attr("fill", "none") + .attr("stroke", strokeColor || "currentColor") + .attr("stroke-width", thickness) + .attr("class", resolveSlot("bar")); + } else { + // Progress fill + svg.append("path") + .attr("d", progressArc as any) + .attr("fill", "none") + .attr("stroke", strokeColor || "currentColor") + .attr("stroke-width", thickness) + .attr("class", resolveSlot("bar")); + } + } + } + + // ----- Variant: multiBar ----- + if (variant === "multiBar" && bars && bars.length > 0) { + const totalThickness = thickness * bars.length + gap * (bars.length - 1); + const startRadius = outerRadius - totalThickness + thickness; + bars.forEach((bar, i) => { + const barThickness = thickness; // shared + const innerR = startRadius + i * (thickness + gap); + const outerR = innerR + barThickness; + const barAngle = valueToAngle(bar.value); + const barArc = d3.arc() + .innerRadius(innerR) + .outerRadius(outerR) + .startAngle(startAngleRad) + .endAngle(barAngle) + .cornerRadius(cornerRadius); + + svg.append("path") + .attr("d", barArc as any) + .attr("fill", "none") + .attr("stroke", bar.color || "currentColor") + .attr("stroke-width", barThickness) + .attr("class", resolveSlot("bar")); + }); + } + + // ----- Needle ----- + const needleShow = needleProps.show !== false && (variant === "needle" || variant === "segmented" || variant === "progress" ? needleProps.show : false); + if (needleShow && value != null) { + const needleAngle = valueToAngle(value); + const needleLength = (() => { + const len = needleProps.length ?? "medium"; + switch (len) { + case "short": return outerRadius * 0.6; + case "medium": return outerRadius * 0.8; + case "full": return outerRadius * 1.05; + default: return len; + } + })(); + const needleWidth = needleProps.width ?? 2; + const capRadius = needleProps.capRadius ?? 4; + const needleColor = needleProps.color ?? "currentColor"; + + // Needle tip coordinates + const tipX = cx + needleLength * Math.cos(needleAngle - Math.PI / 2); + const tipY = cy + needleLength * Math.sin(needleAngle - Math.PI / 2); + + const needleGroup = svg.append("g").attr("class", resolveSlot("needle")); + + // Draw needle line (simple line) + needleGroup.append("line") + .attr("x1", cx) + .attr("y1", cy) + .attr("x2", tipX) + .attr("y2", tipY) + .attr("stroke", needleColor) + .attr("stroke-width", needleWidth) + .attr("stroke-linecap", "round"); + + // Center cap + needleGroup.append("circle") + .attr("cx", cx) + .attr("cy", cy) + .attr("r", capRadius) + .attr("fill", needleColor); + + // Optional: animation (we'll keep simple for now) + } + + // ----- Ticks ----- + if (ticksProps.show) { + const tickCount = ticksProps.count ?? 5; + const tickLength = ticksProps.length ?? 5; + const tickPosition = ticksProps.position ?? "outside"; + const tickAngles = d3.range(tickCount).map(i => { + const ratio = i / (tickCount - 1); + return startAngleRad + ratio * (endAngleRad - startAngleRad); + }); + + tickAngles.forEach(angle => { + const cos = Math.cos(angle - Math.PI / 2); + const sin = Math.sin(angle - Math.PI / 2); + let innerP, outerP; + const baseR = (tickPosition === "inside") ? innerRadius : outerRadius; + if (tickPosition === "inside") { + innerP = { x: cx + (baseR - tickLength) * cos, y: cy + (baseR - tickLength) * sin }; + outerP = { x: cx + baseR * cos, y: cy + baseR * sin }; + } else if (tickPosition === "outside") { + innerP = { x: cx + baseR * cos, y: cy + baseR * sin }; + outerP = { x: cx + (baseR + tickLength) * cos, y: cy + (baseR + tickLength) * sin }; + } else { // cross + innerP = { x: cx + (baseR - tickLength / 2) * cos, y: cy + (baseR - tickLength / 2) * sin }; + outerP = { x: cx + (baseR + tickLength / 2) * cos, y: cy + (baseR + tickLength / 2) * sin }; + } + svg.append("line") + .attr("x1", innerP.x) + .attr("y1", innerP.y) + .attr("x2", outerP.x) + .attr("y2", outerP.y) + .attr("class", resolveSlot("tick")) + .attr("stroke-width", 1); + }); + + if (ticksProps.labels) { + const labelOffset = (ticksProps.position === "outside" ? 15 : -15); + tickAngles.forEach((angle, i) => { + const val = min + (i / (tickCount - 1)) * (max - min); + const cos = Math.cos(angle - Math.PI / 2); + const sin = Math.sin(angle - Math.PI / 2); + const labelR = outerRadius + labelOffset; + const x = cx + labelR * cos; + const y = cy + labelR * sin; + svg.append("text") + .attr("x", x) + .attr("y", y) + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .attr("class", resolveSlot("tickLabel")) + .text(Math.round(val).toString()); + }); + } + } + + // ----- Scale labels (min/max) ----- + if (scaleProps.minLabel || scaleProps.maxLabel) { + // Place labels at the start/end of the arc, outside + const minAngle = startAngleRad; + const maxAngle = endAngleRad; + const labelDist = outerRadius + 20; + const minX = cx + labelDist * Math.cos(minAngle - Math.PI / 2); + const minY = cy + labelDist * Math.sin(minAngle - Math.PI / 2); + const maxX = cx + labelDist * Math.cos(maxAngle - Math.PI / 2); + const maxY = cy + labelDist * Math.sin(maxAngle - Math.PI / 2); + + if (scaleProps.minLabel) { + svg.append("text") + .attr("x", minX) + .attr("y", minY) + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .attr("class", resolveSlot("tickLabel")) + .text(scaleProps.minLabel); + } + if (scaleProps.maxLabel) { + svg.append("text") + .attr("x", maxX) + .attr("y", maxY) + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .attr("class", resolveSlot("tickLabel")) + .text(scaleProps.maxLabel); + } + } + + }, [ + value, variant, min, max, effectiveWidth, effectiveHeight, + arcProps, trackProps, fillMode, bars, needleProps, segments, + thresholds, gradient, ticksProps, scaleProps, resolveSlot + ]); + + // ----- Center value text (HTML) ----- + const displayValue = useMemo(() => { + if (value == null) return "β€”"; + if (valueLabelProps.formatter) return valueLabelProps.formatter(value); + const prec = valueLabelProps.precision ?? 0; + const num = value.toFixed(prec); + return `${valueLabelProps.prefix ?? ""}${num}${valueLabelProps.suffix ?? ""}`; + }, [value, valueLabelProps]); + + // ----- Needle label (HTML) ----- + const needleLabelText = useMemo(() => { + if (!needleLabelProps.show || value == null) return null; + if (needleLabelProps.formatter) return needleLabelProps.formatter(value); + return `${value}`; + }, [value, needleLabelProps]); + + // ----- Render ----- + return ( +
onHover?.(true)} + onMouseLeave={() => onHover?.(false)} + > + {title && {title}} + + {loading ? ( +
+ +
+ ) : error ? ( + {error} + ) : ( + <> + + + {/* Center value (HTML overlay) */} + {valueLabelProps.show !== false && ( +
+ + {displayValue} + + {needleLabelText && ( + + {needleLabelText} + + )} +
+ )} + + )} + + {/* Tooltip placeholder */} + {tooltip?.show && ( +
+ {/* D3 tooltip handling can be added later */} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/src/hooks/useResizeObserver.ts b/src/hooks/useResizeObserver.ts new file mode 100644 index 00000000..be0198ec --- /dev/null +++ b/src/hooks/useResizeObserver.ts @@ -0,0 +1,36 @@ +import { useRef, useEffect, useState } from "react"; + +interface ElementSize { + width: number; + height: number; +} + +export function useResizeObserver(): { + ref: React.RefObject; + width: number; + height: number; +} { + const containerRef = useRef(null); + const [size, setSize] = useState({ width: 0, height: 0 }); + + useEffect(() => { + const node = containerRef.current; + if (!node) return; + + // Create the observer (non‑generic) + const observer = new ResizeObserver((entries) => { + if (!entries.length) return; + const { width, height } = entries[0].contentRect; + setSize({ width, height }); + }); + + observer.observe(node); + + // Cleanup + return () => { + observer.disconnect(); + }; + }, []); // empty dependency β†’ runs once after mount + + return { ref: containerRef, ...size }; +} \ No newline at end of file diff --git a/src/styles/base.css b/src/styles/base.css index d08001bb..34769c57 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -51,3 +51,68 @@ container-name: anedya-card; --anedya-card-gap: 1rem; } } + +.anedya-gauge { + container-type: inline-size; + container-name: anedya-gauge; + + /* Sizing */ + --anedya-gauge-padding: 1rem; + --anedya-gauge-title-size: 0.875rem; + + /* Arc */ + --anedya-gauge-track-stroke: #e2e8f0; + --anedya-gauge-track-fill: transparent; + --anedya-gauge-bar-stroke: #3b82f6; + --anedya-gauge-bar-fill: transparent; + --anedya-gauge-thickness: 12; + + /* Needle */ + --anedya-gauge-needle-color: #334155; + --anedya-gauge-needle-cap-color: #334155; + + /* Center value */ + --anedya-gauge-center-value-size: 2rem; + --anedya-gauge-center-value-weight: 700; + --anedya-gauge-center-value-color: #1e293b; + + /* Needle label */ + --anedya-gauge-needle-label-size: 0.75rem; + --anedya-gauge-needle-label-color: #64748b; + + /* Ticks */ + --anedya-gauge-tick-stroke: #94a3b8; + --anedya-gauge-tick-label-size: 0.625rem; + --anedya-gauge-tick-label-color: #64748b; + + /* Segments */ + --anedya-gauge-segment-stroke: #e2e8f0; + + --anedya-gauge-gap: 0.5rem; +} + +/* Container queries scale typography (like Card) */ +@container anedya-gauge(min-width: 280px) { + .anedya-gauge { + --anedya-gauge-title-size: 0.9375rem; + --anedya-gauge-center-value-size: 2.25rem; + --anedya-gauge-needle-label-size: 0.8125rem; + --anedya-gauge-tick-label-size: 0.6875rem; + } +} +@container anedya-gauge(min-width: 400px) { + .anedya-gauge { + --anedya-gauge-title-size: 1.0625rem; + --anedya-gauge-center-value-size: 2.75rem; + --anedya-gauge-needle-label-size: 0.875rem; + --anedya-gauge-tick-label-size: 0.75rem; + } +} +@container anedya-gauge(min-width: 560px) { + .anedya-gauge { + --anedya-gauge-title-size: 1.1875rem; + --anedya-gauge-center-value-size: 3.25rem; + --anedya-gauge-needle-label-size: 1rem; + --anedya-gauge-tick-label-size: 0.875rem; + } +} \ No newline at end of file diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts new file mode 100644 index 00000000..2fb5c7ea --- /dev/null +++ b/src/themes/gaugeTheme.ts @@ -0,0 +1,63 @@ +import { SlotClassNames, WidgetTheme } from "../types/root"; + +// The exact same slot names we'll use in the widget +export type GaugeSlot = + | "container" + | "title" + | "track" + | "bar" + | "needle" + | "centerValue" + | "needleLabel" + | "tick" + | "tickLabel" + | "segment"; + +export const GAUGE_DEFAULT_CLASSES: Record = { + container: + "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-gauge-padding)] gap-[var(--anedya-gauge-gap)]", + title: + "text-[length:var(--anedya-gauge-title-size)] font-medium", + track: + "[stroke:var(--anedya-gauge-track-stroke)] [fill:var(--anedya-gauge-track-fill)]", + bar: + "[stroke:var(--anedya-gauge-bar-stroke)] [fill:var(--anedya-gauge-bar-fill)]", + needle: + "[fill:var(--anedya-gauge-needle-color)] [stroke:var(--anedya-gauge-needle-color)]", + centerValue: + "text-[length:var(--anedya-gauge-center-value-size)] font-[var(--anedya-gauge-center-value-weight)] text-[var(--anedya-gauge-center-value-color)]", + needleLabel: + "text-[length:var(--anedya-gauge-needle-label-size)] text-[var(--anedya-gauge-needle-label-color)]", + tick: + "[stroke:var(--anedya-gauge-tick-stroke)]", + tickLabel: + "text-[length:var(--anedya-gauge-tick-label-size)] text-[var(--anedya-gauge-tick-label-color)] fill-[var(--anedya-gauge-tick-label-color)]", + segment: + "[stroke:var(--anedya-gauge-segment-stroke)]", +}; + +export const lightTheme: WidgetTheme = { + classNames: { + container: "bg-white border-slate-200", + title: "text-slate-500", + centerValue: "text-slate-900", + needleLabel: "text-slate-400", + tickLabel: "fill-slate-400 text-slate-400", + }, +}; + +export const darkTheme: WidgetTheme = { + classNames: { + container: "bg-slate-900 border-slate-800", + title: "text-slate-400", + centerValue: "text-white", + needleLabel: "text-slate-500", + tickLabel: "fill-slate-500 text-slate-500", + }, +}; + +export const gaugeThemes = { + light: lightTheme, + dark: darkTheme, +} as const; +export type GaugeThemeName = keyof typeof gaugeThemes; \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index bb52c051..25c2e06b 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -1,11 +1,7 @@ - - - - import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; - +import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = @@ -22,7 +18,7 @@ const node = anedya.newNode(client, nodeId); * app. Only specify the slots you actually want to change from the * built-in default β€” anything omitted falls back to lightTheme/darkTheme. */ -const emeraldTheme= { +const emeraldTheme = { classNames: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", @@ -35,21 +31,35 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
+
{/* ============================================================ * 1. Default appearance β€” no theme, no classNames, no * formatting props. Every fallback in the widget in one place. * ============================================================ */} - + {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same * effect across every widget instance that uses it. * ============================================================ */} - + {/* Built-in preset names also work directly: */} - + {/* ============================================================ * 3. classNames vs className β€” THE distinction to understand: @@ -121,6 +131,47 @@ export default function App() { value: "my-card-value", }} /> + + {/* */} + + {/* Needle gauge with threshold colors */} + {/* */} + + {/* Segmented gauge */} + {/* */} + + {/* Multi-bar */} + {/* */} + + {/* Responsive – will resize to its container */} + {/*
+ +
*/}
); } From f21b15bbe6b344232a78ed3e7072e1067322d153 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Thu, 23 Jul 2026 13:38:27 +0530 Subject: [PATCH 23/66] build error fix --- dist/index.js | 93 +++++++++++++++++++---------------- dist/index.mjs | 93 +++++++++++++++++++---------------- dist/style.css | 2 +- src/components/CardWidget.tsx | 20 +++++--- src/styles/base.css | 17 +++---- test/my-app/src/App.jsx | 4 +- 6 files changed, 125 insertions(+), 104 deletions(-) diff --git a/dist/index.js b/dist/index.js index afcd91ab..e6043277 100644 --- a/dist/index.js +++ b/dist/index.js @@ -161,14 +161,10 @@ function CardWidget({ const d = timestamp < 1e12 ? new Date(timestamp * 1e3) : new Date(timestamp); return `Updated ${d.toLocaleTimeString()}`; }, [timestamp, resolvedProps.labelText]); - return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( + return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( "div", { - className: (0, import_tailwind_merge.twMerge)( - "anedya-card", - resolveSlot("container"), - resolvedProps.className - ), + className: "anedya-card-container", style: { width: resolvedProps.width, minWidth: resolvedProps.minWidth, @@ -176,44 +172,55 @@ function CardWidget({ height: resolvedProps.height, boxSizing: "border-box" }, - children: [ - /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("title"), children: resolvedProps.title }), - loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( - "div", - { - style: { - height: 36, - width: 36, - borderRadius: "50%", - border: "2px solid #cbd5e1", - borderTopColor: "#475569", - animation: "anedya-card-spin 0.8s linear infinite" - }, - children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) - } - ) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ - /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( - "span", - { - className: (0, import_tailwind_merge.twMerge)( - "inline-flex items-end justify-center gap-1", - resolveSlot("value") - ), - children: [ - /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: displayValue }), - resolvedProps.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) - ] - } + children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( + "div", + { + className: (0, import_tailwind_merge.twMerge)( + "anedya-card", + resolveSlot("container"), + resolvedProps.className ), - displayLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( - "span", - { - className: resolveSlot("label"), - children: displayLabel - } - ) - ] }) - ] + style: { height: "100%" }, + children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("title"), children: resolvedProps.title }), + loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( + "div", + { + style: { + height: 36, + width: 36, + borderRadius: "50%", + border: "2px solid #cbd5e1", + borderTopColor: "#475569", + animation: "anedya-card-spin 0.8s linear infinite" + }, + children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) + } + ) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( + "span", + { + className: (0, import_tailwind_merge.twMerge)( + "inline-flex items-end justify-center gap-1", + resolveSlot("value") + ), + children: [ + /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: displayValue }), + resolvedProps.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) + ] + } + ), + displayLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( + "span", + { + className: resolveSlot("label"), + children: displayLabel + } + ) + ] }) + ] + } + ) } ); } diff --git a/dist/index.mjs b/dist/index.mjs index 9ee0c262..6c63ea3d 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -135,14 +135,10 @@ function CardWidget({ const d = timestamp < 1e12 ? new Date(timestamp * 1e3) : new Date(timestamp); return `Updated ${d.toLocaleTimeString()}`; }, [timestamp, resolvedProps.labelText]); - return /* @__PURE__ */ jsxs( + return /* @__PURE__ */ jsx( "div", { - className: twMerge( - "anedya-card", - resolveSlot("container"), - resolvedProps.className - ), + className: "anedya-card-container", style: { width: resolvedProps.width, minWidth: resolvedProps.minWidth, @@ -150,44 +146,55 @@ function CardWidget({ height: resolvedProps.height, boxSizing: "border-box" }, - children: [ - /* @__PURE__ */ jsx("span", { className: resolveSlot("title"), children: resolvedProps.title }), - loading ? /* @__PURE__ */ jsx( - "div", - { - style: { - height: 36, - width: 36, - borderRadius: "50%", - border: "2px solid #cbd5e1", - borderTopColor: "#475569", - animation: "anedya-card-spin 0.8s linear infinite" - }, - children: /* @__PURE__ */ jsx("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) - } - ) : error ? /* @__PURE__ */ jsx("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ jsxs(Fragment, { children: [ - /* @__PURE__ */ jsxs( - "span", - { - className: twMerge( - "inline-flex items-end justify-center gap-1", - resolveSlot("value") - ), - children: [ - /* @__PURE__ */ jsx("span", { children: displayValue }), - resolvedProps.unit && /* @__PURE__ */ jsx("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) - ] - } + children: /* @__PURE__ */ jsxs( + "div", + { + className: twMerge( + "anedya-card", + resolveSlot("container"), + resolvedProps.className ), - displayLabel && /* @__PURE__ */ jsx( - "span", - { - className: resolveSlot("label"), - children: displayLabel - } - ) - ] }) - ] + style: { height: "100%" }, + children: [ + /* @__PURE__ */ jsx("span", { className: resolveSlot("title"), children: resolvedProps.title }), + loading ? /* @__PURE__ */ jsx( + "div", + { + style: { + height: 36, + width: 36, + borderRadius: "50%", + border: "2px solid #cbd5e1", + borderTopColor: "#475569", + animation: "anedya-card-spin 0.8s linear infinite" + }, + children: /* @__PURE__ */ jsx("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) + } + ) : error ? /* @__PURE__ */ jsx("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ jsxs(Fragment, { children: [ + /* @__PURE__ */ jsxs( + "span", + { + className: twMerge( + "inline-flex items-end justify-center gap-1", + resolveSlot("value") + ), + children: [ + /* @__PURE__ */ jsx("span", { children: displayValue }), + resolvedProps.unit && /* @__PURE__ */ jsx("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) + ] + } + ), + displayLabel && /* @__PURE__ */ jsx( + "span", + { + className: resolveSlot("label"), + children: displayLabel + } + ) + ] }) + ] + } + ) } ); } diff --git a/dist/style.css b/dist/style.css index 4fea5a80..f50342b9 100644 --- a/dist/style.css +++ b/dist/style.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card-container{container:anedya-card/inline-size}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem}@container anedya-card (min-width:320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card (min-width:420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 276c9a29..49de2379 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -223,18 +223,23 @@ export function CardWidget({ }, [timestamp, resolvedProps.labelText]); return (
+
{resolvedProps.title} @@ -291,5 +296,6 @@ export function CardWidget({ )}
+
); } diff --git a/src/styles/base.css b/src/styles/base.css index d08001bb..53a4292d 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -10,23 +10,22 @@ @source "../common.ts"; /* ---------- Widget defaults ---------- */ - -.anedya-card { +.anedya-card-container { container-type: inline-size; -container-name: anedya-card; + container-name: anedya-card; +} - --anedya-card-padding: 1rem; +.anedya-card { + --anedya-card-padding: 1rem; --anedya-card-title-size: .875rem; --anedya-card-value-size: 2.25rem; --anedya-card-unit-size: 1rem; --anedya-card-label-size: .75rem; - --anedya-card-gap: .5rem; } - -@container anedya-card(min-width: 320px) { +@container anedya-card (min-width: 320px) { .anedya-card { --anedya-card-padding: 1.25rem; @@ -39,12 +38,12 @@ container-name: anedya-card; } } -@container anedya-card(min-width: 420px) { +@container anedya-card (min-width: 420px) { .anedya-card { --anedya-card-padding: 1.5rem; --anedya-card-title-size: 1.125rem; - --anedya-card-value-size: 3.5rem; +--anedya-card-value-size: 5rem; --anedya-card-unit-size: 1.25rem; --anedya-card-label-size: 1rem; diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index a5ea8de8..9a416f5f 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -39,7 +39,8 @@ export default function App() { * 1. Default appearance β€” no theme, no classNames, no * formatting props. Every fallback in the widget in one place. * ============================================================ */} - + + {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same @@ -79,6 +80,7 @@ export default function App() { value: "text-red-500 text-5xl", // <- targets the INNER "value" slot specifically title: "uppercase tracking-wider", // <- targets the INNER "title" slot specifically }} + /> {/* ============================================================ From 0930a7cd8ad76b6181e00b5293b40782a869f0e4 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Thu, 23 Jul 2026 15:30:07 +0530 Subject: [PATCH 24/66] Fix build error --- dist/index.d.mts | 122 ++++++++++++++++++++++++++++++++++++++++++++++ dist/index.d.ts | 122 ++++++++++++++++++++++++++++++++++++++++++++++ dist/style.css | 2 + package-lock.json | 26 +++++++++- package.json | 10 ++-- ts.config.json | 1 + 6 files changed, 277 insertions(+), 6 deletions(-) create mode 100644 dist/index.d.mts create mode 100644 dist/index.d.ts create mode 100644 dist/style.css diff --git a/dist/index.d.mts b/dist/index.d.mts new file mode 100644 index 00000000..80d3c097 --- /dev/null +++ b/dist/index.d.mts @@ -0,0 +1,122 @@ +import * as react from 'react'; + +type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; +type BuiltInTheme = "light" | "dark"; + +/** + * Generic per-slot class overrides. Every widget defines its own slot + * names (Card: container/title/value/unit/label, Chart: container/line/ + * axis/...) but they all share this same shape. + */ +type SlotClassNames = Partial>; +/** + * A widget theme is simply a reusable collection of Tailwind (or plain + * CSS) classes for a widget's slots. + * + * Themes are merged in three layers: + * + * built-in theme + * ↓ + * user theme + * ↓ + * widget classNames prop + * + * Later layers win via `twMerge`. + */ +interface WidgetTheme { + classNames: SlotClassNames; +} + +/** + * Every widget takes this shape as its base. Widget-specific props + * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * rather than repeating client/node/sizing/theme plumbing per widget. + * + * `node` is required directly (built by the consumer via + * `anedya.newNode(client, nodeId)`) rather than derived internally β€” + * keeps node/rate-limiting construction fully in the consumer's control, + * outside the widget. + */ +interface AnedyaWidgetBaseProps { + node: any; + variable: string; + /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ + from?: number; + to?: number; + limit?: number; + title?: string; + /** + * Optional theme for the widget. + * + * A theme is a reusable collection of classes for the widget's slots. + * It is merged with the widget's built-in defaults, while the + * `classNames` prop is applied afterwards for per-instance overrides. + */ + theme?: WidgetTheme | BuiltInTheme; + /** Applied to the widget's outermost element, on top of everything else. */ + className?: string; + width?: number; + height?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + aspectRatio?: number; +} + +type CardSlot = "container" | "title" | "value" | "unit" | "label"; +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +interface CardData { + value: number; + timestamp: number; +} +type CardWidgetUpdate = Partial>; +interface CardWidgetProps extends AnedyaWidgetBaseProps { + unit?: string; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + precision?: number; + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + classNames?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * classNames: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; +} +declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react.JSX.Element; + +export { CardWidget }; diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 00000000..80d3c097 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,122 @@ +import * as react from 'react'; + +type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; +type BuiltInTheme = "light" | "dark"; + +/** + * Generic per-slot class overrides. Every widget defines its own slot + * names (Card: container/title/value/unit/label, Chart: container/line/ + * axis/...) but they all share this same shape. + */ +type SlotClassNames = Partial>; +/** + * A widget theme is simply a reusable collection of Tailwind (or plain + * CSS) classes for a widget's slots. + * + * Themes are merged in three layers: + * + * built-in theme + * ↓ + * user theme + * ↓ + * widget classNames prop + * + * Later layers win via `twMerge`. + */ +interface WidgetTheme { + classNames: SlotClassNames; +} + +/** + * Every widget takes this shape as its base. Widget-specific props + * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * rather than repeating client/node/sizing/theme plumbing per widget. + * + * `node` is required directly (built by the consumer via + * `anedya.newNode(client, nodeId)`) rather than derived internally β€” + * keeps node/rate-limiting construction fully in the consumer's control, + * outside the widget. + */ +interface AnedyaWidgetBaseProps { + node: any; + variable: string; + /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ + from?: number; + to?: number; + limit?: number; + title?: string; + /** + * Optional theme for the widget. + * + * A theme is a reusable collection of classes for the widget's slots. + * It is merged with the widget's built-in defaults, while the + * `classNames` prop is applied afterwards for per-instance overrides. + */ + theme?: WidgetTheme | BuiltInTheme; + /** Applied to the widget's outermost element, on top of everything else. */ + className?: string; + width?: number; + height?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + aspectRatio?: number; +} + +type CardSlot = "container" | "title" | "value" | "unit" | "label"; +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +interface CardData { + value: number; + timestamp: number; +} +type CardWidgetUpdate = Partial>; +interface CardWidgetProps extends AnedyaWidgetBaseProps { + unit?: string; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + precision?: number; + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + classNames?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * classNames: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; +} +declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react.JSX.Element; + +export { CardWidget }; diff --git a/dist/style.css b/dist/style.css new file mode 100644 index 00000000..5d136a33 --- /dev/null +++ b/dist/style.css @@ -0,0 +1,2 @@ +/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:0}.top-0{top:0}.left-0{left:0}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.block{display:block}.contents{display:contents}.flex{display:flex}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-full{height:100%}.w-full{width:100%}.shrink{flex-shrink:1}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.gap-\[var\(--anedya-gauge-gap\)\]{gap:var(--anedya-gauge-gap)}.rounded{border-radius:.25rem}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.\[fill\:var\(--anedya-gauge-bar-fill\)\]{fill:var(--anedya-gauge-bar-fill)}.\[fill\:var\(--anedya-gauge-needle-color\)\]{fill:var(--anedya-gauge-needle-color)}.\[fill\:var\(--anedya-gauge-track-fill\)\]{fill:var(--anedya-gauge-track-fill)}.fill-\[var\(--anedya-gauge-tick-label-color\)\]{fill:var(--anedya-gauge-tick-label-color)}.fill-slate-400{fill:var(--color-slate-400)}.fill-slate-500{fill:var(--color-slate-500)}.\[stroke\:var\(--anedya-gauge-bar-stroke\)\]{stroke:var(--anedya-gauge-bar-stroke)}.\[stroke\:var\(--anedya-gauge-needle-color\)\]{stroke:var(--anedya-gauge-needle-color)}.\[stroke\:var\(--anedya-gauge-segment-stroke\)\]{stroke:var(--anedya-gauge-segment-stroke)}.\[stroke\:var\(--anedya-gauge-tick-stroke\)\]{stroke:var(--anedya-gauge-tick-stroke)}.\[stroke\:var\(--anedya-gauge-track-stroke\)\]{stroke:var(--anedya-gauge-track-stroke)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.p-\[var\(--anedya-gauge-padding\)\]{padding:var(--anedya-gauge-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.text-\[length\:var\(--anedya-gauge-center-value-size\)\]{font-size:var(--anedya-gauge-center-value-size)}.text-\[length\:var\(--anedya-gauge-needle-label-size\)\]{font-size:var(--anedya-gauge-needle-label-size)}.text-\[length\:var\(--anedya-gauge-tick-label-size\)\]{font-size:var(--anedya-gauge-tick-label-size)}.text-\[length\:var\(--anedya-gauge-title-size\)\]{font-size:var(--anedya-gauge-title-size)}.font-\[var\(--anedya-gauge-center-value-weight\)\]{--tw-font-weight:var(--anedya-gauge-center-value-weight);font-weight:var(--anedya-gauge-center-value-weight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-\[var\(--anedya-gauge-center-value-color\)\]{color:var(--anedya-gauge-center-value-color)}.text-\[var\(--anedya-gauge-needle-label-color\)\]{color:var(--anedya-gauge-needle-label-color)}.text-\[var\(--anedya-gauge-tick-label-color\)\]{color:var(--anedya-gauge-tick-label-color)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}.anedya-gauge{--anedya-gauge-padding:1rem;--anedya-gauge-title-size:.875rem;--anedya-gauge-track-stroke:#e2e8f0;--anedya-gauge-track-fill:transparent;--anedya-gauge-bar-stroke:#3b82f6;--anedya-gauge-bar-fill:transparent;--anedya-gauge-thickness:12;--anedya-gauge-needle-color:#334155;--anedya-gauge-needle-cap-color:#334155;--anedya-gauge-center-value-size:2rem;--anedya-gauge-center-value-weight:700;--anedya-gauge-center-value-color:#1e293b;--anedya-gauge-needle-label-size:.75rem;--anedya-gauge-needle-label-color:#64748b;--anedya-gauge-tick-stroke:#94a3b8;--anedya-gauge-tick-label-size:.625rem;--anedya-gauge-tick-label-color:#64748b;--anedya-gauge-segment-stroke:#e2e8f0;--anedya-gauge-gap:.5rem;container:anedya-gauge/inline-size}@container anedya-gauge(min-width: 280px){.anedya-gauge{--anedya-gauge-title-size:.9375rem;--anedya-gauge-center-value-size:2.25rem;--anedya-gauge-needle-label-size:.8125rem;--anedya-gauge-tick-label-size:.6875rem}}@container anedya-gauge(min-width: 400px){.anedya-gauge{--anedya-gauge-title-size:1.0625rem;--anedya-gauge-center-value-size:2.75rem;--anedya-gauge-needle-label-size:.875rem;--anedya-gauge-tick-label-size:.75rem}}@container anedya-gauge(min-width: 560px){.anedya-gauge{--anedya-gauge-title-size:1.1875rem;--anedya-gauge-center-value-size:3.25rem;--anedya-gauge-needle-label-size:1rem;--anedya-gauge-tick-label-size:.875rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 74038084..885514ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,8 @@ "devDependencies": { "@base-ui/react": "^1.6.0", "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", @@ -1924,6 +1926,27 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, "node_modules/acorn": { "version": "8.17.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", @@ -2070,8 +2093,7 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/d3": { "version": "7.9.0", diff --git a/package.json b/package.json index e3ade950..f48cf139 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,10 @@ "./styles.css": "./dist/styles.css" }, "scripts": { - "clean": "rm -rf dist", - "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify", - "build:js": "tsup", - "build": "npm run clean && npm run build:js && npm run build:css", + "clean": "rm -rf dist", + "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify", + "build:js": "tsup", + "build": "npm run clean && npm run build:js && npm run build:css", "typecheck": "tsc --noEmit" }, "repository": { @@ -45,6 +45,8 @@ "devDependencies": { "@base-ui/react": "^1.6.0", "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", diff --git a/ts.config.json b/ts.config.json index a2224bc5..51b07b33 100644 --- a/ts.config.json +++ b/ts.config.json @@ -5,6 +5,7 @@ "module": "ESNext", "moduleResolution": "Bundler", "jsx": "react-jsx", + "types":["react", "react-dom"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, From bf388e247e36ca4563e03bc08662a296e8289ca5 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 08:42:19 +0530 Subject: [PATCH 25/66] updated responsiveness and added read me and license --- .gitignore | 3 + LICENSE | 222 +--- README.md | 143 ++- dist/index.d.mts | 169 +-- dist/index.d.ts | 122 -- dist/index.js | 230 ---- dist/index.mjs | 372 +++--- dist/style.css | 2 - package-lock.json | 2141 +++++++++++++++------------------ package.json | 19 +- public-widget-sdk@5.5.0 | 0 rollup | 0 src/common.ts | 9 +- src/components/CardWidget.tsx | 102 +- src/styles/base.css | 52 +- src/themes/defaultTheme.ts | 7 +- src/types/root.ts | 4 +- test/my-app/.env.example | 3 + test/my-app/.gitignore | 1 + test/my-app/package-lock.json | 1086 +++++++++++------ test/my-app/package.json | 3 +- test/my-app/src/App.jsx | 84 +- test/my-app/vite.config.js | 6 + ts.config.json | 4 +- tsdown.config.ts | 13 + tsup.config.ts | 10 - 26 files changed, 2243 insertions(+), 2564 deletions(-) delete mode 100644 dist/index.d.ts delete mode 100644 dist/index.js delete mode 100644 dist/style.css delete mode 100644 public-widget-sdk@5.5.0 delete mode 100644 rollup create mode 100644 test/my-app/.env.example create mode 100644 tsdown.config.ts delete mode 100644 tsup.config.ts diff --git a/.gitignore b/.gitignore index eedb7144..b65549ce 100644 --- a/.gitignore +++ b/.gitignore @@ -5,14 +5,17 @@ /.pnp .pnp.js + # testing /coverage # production /build +/dist # misc .DS_Store +.env .env.local .env.development.local .env.test.local diff --git a/LICENSE b/LICENSE index 261eeb9e..7bce2a58 100644 --- a/LICENSE +++ b/LICENSE @@ -1,201 +1,21 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +MIT License + +Copyright (c) 2026 Anedya Systems + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 087823bd..6a0cc425 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,35 @@ A single-value display widget for Anedya data β€” shows the latest reading, a title, and a last-updated label. +## Table of Contents + +- [Setup](#setup) +- [Required props](#required-props) +- [The styling model](#the-styling-model) +- [`styles` vs `className`](#styles-vs-classname--the-distinction-that-matters-most) +- [Theming](#theming) +- [Tailwind responsive utilities](#tailwind-responsive-utilities) +- [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) +- [How props are resolved](#how-props-are-resolved) +- [Formatting vs rendering](#formatting-vs-rendering) +- [Sizing](#sizing) +- [Responsive sizing](#responsive-sizing) +- [Loading & error states](#loading--error-states) +- [Other props](#other-props) +- [Build & distribution](#build--distribution--why-classes-render-unstyled-without-this) + +--- ## Setup -The widget doesn't create its own SDK client or node β€” you create both yourself and pass the node in: +`CardWidget` doesn't create its own SDK client or node β€” it only renders data you fetch through the [Anedya Frontend SDK](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk), which is a separate package you'll need alongside this one. + +**1. Install both packages:** + +```bash +npm install @anedyasystems/anedya-frontend-sdk your-sdk +``` + +**2. Create a client and node using the Frontend SDK, then pass the node into `CardWidget`:** ```jsx import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; @@ -18,6 +44,10 @@ const node = anedya.newNode(client, nodeId); ``` +> `tokenId`, `token`, and `nodeId` come from your Anedya account/device setup β€” see the [Frontend SDK docs](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk) for details on obtaining these and on other `node`/`client` methods (fetching historical data, live streaming, key-value store, etc.) beyond what this widget itself uses. + +--- + ## Required props | Prop | Type | Description | @@ -25,9 +55,11 @@ const node = anedya.newNode(client, nodeId); | `node` | `any` | `anedya.newNode(client, nodeId)` | | `variable` | `string` | Variable name to display | +--- + ## The styling model -Unlike `ChartWidget` (which uses inline `style` objects), `CardWidget` is **entirely class-based** β€” every visual choice is a CSS class string, not a style property. This is deliberate: Card widgets are commonly styled with Tailwind, and classes compose and override far more predictably than inline styles do once you're combining a theme, a per-instance override, and a conditional rule all on the same element. +`CardWidget` is **entirely class-based** β€” every visual choice is a CSS class string, not a style property. This is deliberate: card widgets are commonly styled with Tailwind, and classes compose and override far more predictably than inline styles do once you're combining a theme, a per-instance override, and a conditional rule all on the same element. Every part of the card is a named **slot**: @@ -35,34 +67,40 @@ Every part of the card is a named **slot**: type CardSlot = "container" | "title" | "value" | "unit" | "label"; ``` -## `classNames` vs `className` β€” the distinction that matters most +--- + +## `styles` vs `className` β€” the distinction that matters most These look similar but do genuinely different things: | | Shape | Targets | Purpose | |---|---|---|---| -| `classNames` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) *and* `container` | reach inside the widget | +| `styles` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) *and* `container` | reach inside the widget | | `className` | plain string | only the outermost container element | the ordinary React convention every component supports | ```jsx ``` -Both can be used together freely β€” `className` is merged (via `twMerge`) with whatever `classNames.container` already resolved to; it doesn't replace it. +Both can be used together freely β€” `className` is merged (via `twMerge`) with whatever `styles.container` already resolved to; it doesn't replace it. + +> **Note:** `styles` classes are consumer-authored strings forwarded straight into `className` at render β€” the widget doesn't generate any CSS for them at build time. Any class you pass here must already exist in your own app's compiled CSS (e.g. your own Tailwind build, or a plain hand-written class in a stylesheet you import) β€” arbitrary utility names that only the widget's *own* Tailwind build knows about (like the container-query variables described below) won't do anything if typed fresh from a consuming app. + +--- ## Theming -`theme` accepts a built-in preset name, or a full custom `WidgetTheme` object β€” just a plain object shaped like `classNames`, reusable across every widget instance that uses it: +`theme` accepts a built-in preset name, or a full custom `WidgetTheme` object β€” just a plain object shaped like `styles`, reusable across every widget instance that uses it: ```jsx const emeraldTheme: WidgetTheme = { - classNames: { + styles: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", value: "text-emerald-900", @@ -75,25 +113,28 @@ const emeraldTheme: WidgetTheme = { // built-in preset, or "light" (default) ``` +--- + ## Tailwind responsive utilities -You can freely use Tailwind's responsive prefixes inside `classNames`: +You can freely use Tailwind's responsive prefixes inside `styles`: ```tsx ``` -These breakpoints come entirely from your application's Tailwind configuration and respond to the browser viewport. - -They are independent of the widget's built-in container-query sizing. +These breakpoints come entirely from your application's Tailwind configuration and respond to the **browser viewport**. They are independent of the widget's built-in container-query sizing (see [Responsive sizing](#responsive-sizing) below). If you supply your own `text-*` classes (responsive or otherwise), they replace the widget's default responsive typography for that slot. +--- + ## `onDataChange` β€” data-driven rendering + `onDataChange` is called whenever the latest fetched data changes. It receives the raw fetched data: @@ -117,7 +158,7 @@ Instead of returning CSS classes, it returns a **partial set of widget props**. return { title: "High Humidity", theme: "dark", - classNames: { + styles: { value: "text-red-500", }, }; @@ -128,6 +169,8 @@ Instead of returning CSS classes, it returns a **partial set of widget props**. Returning `undefined` (or nothing) clears any previous overrides and restores the widget's original props. +--- + ## How props are resolved Rendering happens in layers. @@ -141,19 +184,21 @@ For each slot (`container`, `title`, `value`, `unit`, `label`), classes are merg 1. `CARD_DEFAULT_CLASSES` 2. Active theme classes -3. `classNames` +3. `styles` Later layers win whenever two Tailwind utilities conflict. Conflicts are resolved with `twMerge`. -`className` is separate from this chainβ€”it is merged onto the outer container after the container slot has been resolved. +`className` is separate from this chain β€” it is merged onto the outer container after the container slot has been resolved. -> **Rule of thumb:** defaults β†’ theme β†’ `classNames` β†’ `onDataChange`. User overrides always win. +> **Rule of thumb:** defaults β†’ theme β†’ `styles` β†’ `onDataChange`. User overrides always win. + +--- ## Formatting vs rendering `formatValue` and `labelText` control **what text is displayed**. -`classNames` controls **how the widget looks**. +`styles` controls **how the widget looks**. `onDataChange` can override either one (along with most other widget props), allowing the widget to react to incoming data. @@ -169,7 +214,7 @@ For example: if (data.value > 80) { return { title: "High Humidity", - classNames: { + styles: { value: "text-red-500", }, }; @@ -178,16 +223,42 @@ For example: /> ``` +> Long `formatValue` output (e.g. `"56.00 % RH"`) may wrap onto a second line at small widths β€” the value slot wraps rather than overflowing. See [Sizing](#sizing) for how this interacts with a fixed `height`. + +--- + ## Sizing -`width`/`height`/`minWidth`/`maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole classNames/theme system, same convention as `ChartWidget`: +`width` / `height` / `minWidth` / `maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole `styles`/theme system: ```jsx ``` + +### `height` has two distinct modes + +Whether you pass `height` changes how the card behaves β€” this is intentional, not a quirk: + +| | Behavior | +|---|---| +| **`height` omitted** | The card **auto-grows** to fit its content. If `formatValue`/`labelText` produce long text that wraps, the card simply becomes taller. Sizing scales with **width only**. | +| **`height` passed** | The card becomes a **fixed-size box**. Sizing scales with **both width and height** (see [Responsive sizing](#responsive-sizing)). If content is too tall to fit (e.g. a long wrapped value at a small height), it is **clipped**, not overflowed β€” the card will not grow past the height you gave it. | + +```jsx +// Auto-height: card grows to fit content, whatever that content turns out to be + + +// Fixed-height: card is exactly 300px tall; content that doesn't fit is clipped + +``` + +If you're using a `formatValue` that can produce long strings, either don't pass a fixed `height` (let the card grow to fit), or pass a `height` generous enough for the wrapped text at your chosen `width`. + +--- + ## Responsive sizing -The widget automatically scales its internal spacing and typography based on the size of the card itself using **CSS Container Queries**. +The widget automatically scales its internal spacing and typography using **CSS Container Queries** β€” based on the card's own rendered size, not the browser viewport. By default the following properties scale automatically: @@ -198,11 +269,11 @@ By default the following properties scale automatically: - label font size - spacing (`gap`) -Unlike Tailwind's `sm:`/`md:` responsive utilities (which respond to the browser viewport), container queries respond to the widget's own rendered width. +**When `height` is omitted**, scaling responds to the card's **width only** (`cqw`). -For example, a card inside a narrow dashboard column will use smaller typography than the same card rendered full-width, even on the same screen. +**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size card renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. -This behavior is built inβ€”you don't need to configure anything. +A card inside a narrow dashboard column will use smaller typography than the same card rendered full-width, even on the same screen β€” this behavior is built in and needs no configuration. ### Overriding responsive sizing @@ -212,7 +283,7 @@ For example: ```tsx @@ -223,14 +294,20 @@ The value will always render at `text-6xl`. Likewise, if you provide responsive Tailwind classes: ```tsx -classNames={{ +styles={{ value: "text-2xl md:text-5xl" }} ``` -your own breakpoint rules take precedence over the widget's default responsive sizing. +your own breakpoint rules take precedence over the widget's default responsive sizing. This follows normal Tailwind behavior β€” your classes always win over the widget defaults. + +--- -This follows normal Tailwind behaviorβ€”your classes always win over the widget defaults. +## Loading & error states + +While the initial fetch is in flight, the card renders a small spinner in place of the value. If the fetch fails or no data is available, the card renders the error message text in place of the value (title and label still render normally). Neither state currently accepts style overrides via `styles` β€” flag it if you need to customize their appearance. + +--- ## Other props @@ -238,7 +315,9 @@ This follows normal Tailwind behaviorβ€”your classes always win over the widget |---|---|---| | `title` | `string` | Card title. Default: `"Latest Value"` | | `unit` | `string` | Unit suffix shown next to the value | -| `precision` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | +| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | + +--- ## Build & distribution β€” why classes render unstyled without this @@ -275,7 +354,7 @@ npm install -D @tailwindcss/cli } ``` -Run it as part of your normal publish/build step (e.g. chain it into `prepublishOnly` or your existing `build` script) so `dist/style.css` always reflects the current source. +Run it as part of your normal publish/build step so `dist/style.css` always reflects the current source. **4. Consumers import it once**, anywhere in their app: @@ -285,6 +364,6 @@ import "your-sdk/dist/style.css"; That's the entire integration on their end β€” no `content` glob changes, no Tailwind config coordination, no knowledge of how this SDK is built internally required. +--- - -- `style` (a plain inline-style object, part of the shared base props every widget accepts) isn't currently wired into the container's render β€” only `className` is. If you need it, flag it and it can be added the same way `className` already works. +- `style` (a plain inline-style object, part of the shared base props every widget accepts) isn't currently wired into the container's render β€” only `className` is. If you need it, flag it and it can be added the same way `className` already works. \ No newline at end of file diff --git a/dist/index.d.mts b/dist/index.d.mts index 37d78af8..48c03f35 100644 --- a/dist/index.d.mts +++ b/dist/index.d.mts @@ -1,8 +1,8 @@ -import * as react_jsx_runtime from 'react/jsx-runtime'; - +//#region src/types/card.d.ts type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; type BuiltInTheme = "light" | "dark"; - +//#endregion +//#region src/types/root.d.ts /** * Generic per-slot class overrides. Every widget defines its own slot * names (Card: container/title/value/unit/label, Chart: container/line/ @@ -19,17 +19,18 @@ type SlotClassNames = Partial>; * ↓ * user theme * ↓ - * widget classNames prop + * widget styles prop * * Later layers win via `twMerge`. */ interface WidgetTheme { - classNames: SlotClassNames; + styles: SlotClassNames; } - +//#endregion +//#region src/common.d.ts /** * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * (e.g. Card's `unit`/`decimalPlaces`, Chart's `tickCount`) extend this * rather than repeating client/node/sizing/theme plumbing per widget. * * `node` is required directly (built by the consumer via @@ -38,85 +39,91 @@ interface WidgetTheme { * outside the widget. */ interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; + node: any; + variable: string; + /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ + from?: number; + to?: number; + limit?: number; + title?: string; + /** + * Optional theme for the widget. + * + * A theme is a reusable collection of classes for the widget's slots. + * It is merged with the widget's built-in defaults, while the + * `styles` prop is applied afterwards for per-instance overrides. + */ + theme?: WidgetTheme | BuiltInTheme; + /** Applied to the widget's outermost element, on top of everything else. */ + className?: string; + width?: number; + /** + * Card height in pixels. + * - If provided: treated as a fixed size. Content that doesn't fit will be clipped. + * - If omitted: the card grows to fit its content naturally. + */ + height?: number; + minWidth?: number; + maxWidth?: number; + minHeight?: number; + maxHeight?: number; + aspectRatio?: number; } - +//#endregion +//#region src/components/CardWidget.d.ts type CardSlot = "container" | "title" | "value" | "unit" | "label"; /** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ interface CardData { - value: number; - timestamp: number; + value: number; + timestamp: number; } type CardWidgetUpdate = Partial>; interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - classNames?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * classNames: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; + unit?: string; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + decimalPlaces?: number; + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + styles?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * styles: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; } -declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react_jsx_runtime.JSX.Element; - -export { CardWidget }; +declare function CardWidget({ node, variable, title, unit, decimalPlaces, formatValue, labelText, styles, onDataChange, theme, className, width, height, minWidth, maxWidth }: CardWidgetProps): React.JSX.Element; +//#endregion +export { CardWidget }; \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index 37d78af8..00000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as react_jsx_runtime from 'react/jsx-runtime'; - -type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; -type BuiltInTheme = "light" | "dark"; - -/** - * Generic per-slot class overrides. Every widget defines its own slot - * names (Card: container/title/value/unit/label, Chart: container/line/ - * axis/...) but they all share this same shape. - */ -type SlotClassNames = Partial>; -/** - * A widget theme is simply a reusable collection of Tailwind (or plain - * CSS) classes for a widget's slots. - * - * Themes are merged in three layers: - * - * built-in theme - * ↓ - * user theme - * ↓ - * widget classNames prop - * - * Later layers win via `twMerge`. - */ -interface WidgetTheme { - classNames: SlotClassNames; -} - -/** - * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this - * rather than repeating client/node/sizing/theme plumbing per widget. - * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. - */ -interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; -} - -type CardSlot = "container" | "title" | "value" | "unit" | "label"; -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -interface CardData { - value: number; - timestamp: number; -} -type CardWidgetUpdate = Partial>; -interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - classNames?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * classNames: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; -} -declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react_jsx_runtime.JSX.Element; - -export { CardWidget }; diff --git a/dist/index.js b/dist/index.js deleted file mode 100644 index e6043277..00000000 --- a/dist/index.js +++ /dev/null @@ -1,230 +0,0 @@ -"use strict"; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); - -// src/index.ts -var index_exports = {}; -__export(index_exports, { - CardWidget: () => CardWidget -}); -module.exports = __toCommonJS(index_exports); - -// src/components/CardWidget.tsx -var import_react = require("react"); -var import_tailwind_merge = require("tailwind-merge"); - -// src/themes/defaultTheme.ts -var CARD_DEFAULT_CLASSES = { - title: "text-[length:var(--anedya-card-title-size)] font-medium", - value: "text-[length:var(--anedya-card-value-size)] font-bold", - unit: "text-[length:var(--anedya-card-unit-size)]", - label: "text-[length:var(--anedya-card-label-size)]", - container: "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" -}; -var lightTheme = { - classNames: { - container: "bg-white border-slate-200", - title: "text-slate-500", - value: "text-slate-900", - label: "text-slate-400" - } -}; -var darkTheme = { - classNames: { - container: "bg-slate-900 border-slate-800", - title: "text-slate-400", - value: "text-white", - label: "text-slate-500" - } -}; - -// src/components/CardWidget.tsx -var import_jsx_runtime = require("react/jsx-runtime"); -var DEFAULT_WIDTH = 240; -var DEFAULT_MIN_WIDTH = 180; -var DEFAULT_MAX_WIDTH = 480; -function CardWidget({ - node, - variable, - title = "Latest Value", - unit, - precision, - formatValue, - labelText, - classNames = {}, - onDataChange, - theme, - className, - width, - height, - minWidth = DEFAULT_MIN_WIDTH, - maxWidth = DEFAULT_MAX_WIDTH -}) { - const [value, setValue] = (0, import_react.useState)(null); - const [timestamp, setTimestamp] = (0, import_react.useState)(null); - const [loading, setLoading] = (0, import_react.useState)(false); - const [error, setError] = (0, import_react.useState)(null); - const [dynamicProps, setDynamicProps] = (0, import_react.useState)({}); - const mountedRef = (0, import_react.useRef)(false); - const isFetchingRef = (0, import_react.useRef)(false); - (0, import_react.useEffect)(() => { - if (!node) return; - mountedRef.current = true; - const fetchLatest = async () => { - if (isFetchingRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - try { - const res = await node.getLatestData(variable); - if (!mountedRef.current) return; - if (res.isSuccess && res.isDataAvailable) { - setValue(res.data.value); - setTimestamp(res.data.timestamp); - } else { - setValue(null); - setError(res.error?.errorMessage ?? "No data available"); - } - } catch (err) { - if (!mountedRef.current) return; - setValue(null); - setError(err?.message ?? "Failed to fetch data"); - } finally { - if (mountedRef.current) { - setLoading(false); - isFetchingRef.current = false; - } - } - }; - fetchLatest(); - return () => { - mountedRef.current = false; - }; - }, [node, variable]); - (0, import_react.useEffect)(() => { - if (!onDataChange) { - setDynamicProps({}); - return; - } - const data = value != null && timestamp != null ? { value, timestamp } : null; - setDynamicProps(onDataChange(data) ?? {}); - }, [value, timestamp, onDataChange]); - const resolvedProps = { - title, - unit, - precision, - formatValue, - labelText, - width: width ?? DEFAULT_WIDTH, - height, - minWidth, - maxWidth, - className, - theme, - ...dynamicProps, - classNames: { - ...classNames ?? {}, - ...dynamicProps.classNames ?? {} - } - }; - const resolvedTheme = resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" ? lightTheme : resolvedProps.theme ?? lightTheme; - const resolveSlot = (slot) => (0, import_tailwind_merge.twMerge)( - CARD_DEFAULT_CLASSES[slot], - resolvedTheme.classNames[slot], - resolvedProps.classNames[slot] - ); - const displayValue = (0, import_react.useMemo)(() => { - if (value == null) return null; - if (resolvedProps.formatValue) return resolvedProps.formatValue(value); - if (resolvedProps.precision != null) - return value.toFixed(resolvedProps.precision); - return String(value); - }, [value, resolvedProps.formatValue, resolvedProps.precision]); - const displayLabel = (0, import_react.useMemo)(() => { - if (timestamp == null) return null; - if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); - const d = timestamp < 1e12 ? new Date(timestamp * 1e3) : new Date(timestamp); - return `Updated ${d.toLocaleTimeString()}`; - }, [timestamp, resolvedProps.labelText]); - return /* @__PURE__ */ (0, import_jsx_runtime.jsx)( - "div", - { - className: "anedya-card-container", - style: { - width: resolvedProps.width, - minWidth: resolvedProps.minWidth, - maxWidth: resolvedProps.maxWidth, - height: resolvedProps.height, - boxSizing: "border-box" - }, - children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( - "div", - { - className: (0, import_tailwind_merge.twMerge)( - "anedya-card", - resolveSlot("container"), - resolvedProps.className - ), - style: { height: "100%" }, - children: [ - /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("title"), children: resolvedProps.title }), - loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)( - "div", - { - style: { - height: 36, - width: 36, - borderRadius: "50%", - border: "2px solid #cbd5e1", - borderTopColor: "#475569", - animation: "anedya-card-spin 0.8s linear infinite" - }, - children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) - } - ) : error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [ - /* @__PURE__ */ (0, import_jsx_runtime.jsxs)( - "span", - { - className: (0, import_tailwind_merge.twMerge)( - "inline-flex items-end justify-center gap-1", - resolveSlot("value") - ), - children: [ - /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: displayValue }), - resolvedProps.unit && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) - ] - } - ), - displayLabel && /* @__PURE__ */ (0, import_jsx_runtime.jsx)( - "span", - { - className: resolveSlot("label"), - children: displayLabel - } - ) - ] }) - ] - } - ) - } - ); -} -// Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - CardWidget -}); diff --git a/dist/index.mjs b/dist/index.mjs index 6c63ea3d..d51d9874 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -1,203 +1,177 @@ -// src/components/CardWidget.tsx import { useEffect, useMemo, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; - -// src/themes/defaultTheme.ts -var CARD_DEFAULT_CLASSES = { - title: "text-[length:var(--anedya-card-title-size)] font-medium", - value: "text-[length:var(--anedya-card-value-size)] font-bold", - unit: "text-[length:var(--anedya-card-unit-size)]", - label: "text-[length:var(--anedya-card-label-size)]", - container: "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" -}; -var lightTheme = { - classNames: { - container: "bg-white border-slate-200", - title: "text-slate-500", - value: "text-slate-900", - label: "text-slate-400" - } -}; -var darkTheme = { - classNames: { - container: "bg-slate-900 border-slate-800", - title: "text-slate-400", - value: "text-white", - label: "text-slate-500" - } -}; - -// src/components/CardWidget.tsx import { Fragment, jsx, jsxs } from "react/jsx-runtime"; -var DEFAULT_WIDTH = 240; -var DEFAULT_MIN_WIDTH = 180; -var DEFAULT_MAX_WIDTH = 480; -function CardWidget({ - node, - variable, - title = "Latest Value", - unit, - precision, - formatValue, - labelText, - classNames = {}, - onDataChange, - theme, - className, - width, - height, - minWidth = DEFAULT_MIN_WIDTH, - maxWidth = DEFAULT_MAX_WIDTH -}) { - const [value, setValue] = useState(null); - const [timestamp, setTimestamp] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [dynamicProps, setDynamicProps] = useState({}); - const mountedRef = useRef(false); - const isFetchingRef = useRef(false); - useEffect(() => { - if (!node) return; - mountedRef.current = true; - const fetchLatest = async () => { - if (isFetchingRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - try { - const res = await node.getLatestData(variable); - if (!mountedRef.current) return; - if (res.isSuccess && res.isDataAvailable) { - setValue(res.data.value); - setTimestamp(res.data.timestamp); - } else { - setValue(null); - setError(res.error?.errorMessage ?? "No data available"); - } - } catch (err) { - if (!mountedRef.current) return; - setValue(null); - setError(err?.message ?? "Failed to fetch data"); - } finally { - if (mountedRef.current) { - setLoading(false); - isFetchingRef.current = false; - } - } - }; - fetchLatest(); - return () => { - mountedRef.current = false; - }; - }, [node, variable]); - useEffect(() => { - if (!onDataChange) { - setDynamicProps({}); - return; - } - const data = value != null && timestamp != null ? { value, timestamp } : null; - setDynamicProps(onDataChange(data) ?? {}); - }, [value, timestamp, onDataChange]); - const resolvedProps = { - title, - unit, - precision, - formatValue, - labelText, - width: width ?? DEFAULT_WIDTH, - height, - minWidth, - maxWidth, - className, - theme, - ...dynamicProps, - classNames: { - ...classNames ?? {}, - ...dynamicProps.classNames ?? {} - } - }; - const resolvedTheme = resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" ? lightTheme : resolvedProps.theme ?? lightTheme; - const resolveSlot = (slot) => twMerge( - CARD_DEFAULT_CLASSES[slot], - resolvedTheme.classNames[slot], - resolvedProps.classNames[slot] - ); - const displayValue = useMemo(() => { - if (value == null) return null; - if (resolvedProps.formatValue) return resolvedProps.formatValue(value); - if (resolvedProps.precision != null) - return value.toFixed(resolvedProps.precision); - return String(value); - }, [value, resolvedProps.formatValue, resolvedProps.precision]); - const displayLabel = useMemo(() => { - if (timestamp == null) return null; - if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); - const d = timestamp < 1e12 ? new Date(timestamp * 1e3) : new Date(timestamp); - return `Updated ${d.toLocaleTimeString()}`; - }, [timestamp, resolvedProps.labelText]); - return /* @__PURE__ */ jsx( - "div", - { - className: "anedya-card-container", - style: { - width: resolvedProps.width, - minWidth: resolvedProps.minWidth, - maxWidth: resolvedProps.maxWidth, - height: resolvedProps.height, - boxSizing: "border-box" - }, - children: /* @__PURE__ */ jsxs( - "div", - { - className: twMerge( - "anedya-card", - resolveSlot("container"), - resolvedProps.className - ), - style: { height: "100%" }, - children: [ - /* @__PURE__ */ jsx("span", { className: resolveSlot("title"), children: resolvedProps.title }), - loading ? /* @__PURE__ */ jsx( - "div", - { - style: { - height: 36, - width: 36, - borderRadius: "50%", - border: "2px solid #cbd5e1", - borderTopColor: "#475569", - animation: "anedya-card-spin 0.8s linear infinite" - }, - children: /* @__PURE__ */ jsx("style", { children: `@keyframes anedya-card-spin { to { transform: rotate(360deg); } }` }) - } - ) : error ? /* @__PURE__ */ jsx("span", { className: "text-red-600 text-sm", children: error }) : /* @__PURE__ */ jsxs(Fragment, { children: [ - /* @__PURE__ */ jsxs( - "span", - { - className: twMerge( - "inline-flex items-end justify-center gap-1", - resolveSlot("value") - ), - children: [ - /* @__PURE__ */ jsx("span", { children: displayValue }), - resolvedProps.unit && /* @__PURE__ */ jsx("span", { className: resolveSlot("unit"), children: resolvedProps.unit }) - ] - } - ), - displayLabel && /* @__PURE__ */ jsx( - "span", - { - className: resolveSlot("label"), - children: displayLabel - } - ) - ] }) - ] - } - ) - } - ); -} -export { - CardWidget +//#region src/themes/defaultTheme.ts +const CARD_DEFAULT_CLASSES = { + title: "text-[length:var(--anedya-card-title-size)] font-medium", + value: "text-[length:var(--anedya-card-value-size)] font-bold max-w-full min-w-0 leading-tight", + unit: "text-[length:var(--anedya-card-unit-size)]", + label: "text-[length:var(--anedya-card-label-size)]", + container: "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" }; +const lightTheme = { styles: { + container: "bg-white border-slate-200", + title: "text-slate-500", + value: "text-slate-900", + label: "text-slate-400" +} }; +const darkTheme = { styles: { + container: "bg-slate-900 border-slate-800", + title: "text-slate-400", + value: "text-white", + label: "text-slate-500" +} }; +//#endregion +//#region src/components/CardWidget.tsx +const DEFAULT_WIDTH = 240; +const DEFAULT_HEIGHT = 160; +const DEFAULT_MIN_WIDTH = 180; +const DEFAULT_MAX_WIDTH = 480; +function CardWidget({ node, variable, title = "Latest Value", unit, decimalPlaces, formatValue, labelText, styles = {}, onDataChange, theme, className, width, height, minWidth = DEFAULT_MIN_WIDTH, maxWidth = DEFAULT_MAX_WIDTH }) { + const [value, setValue] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [dynamicProps, setDynamicProps] = useState({}); + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + useEffect(() => { + if (!node) return; + mountedRef.current = true; + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + try { + const res = await node.getLatestData(variable); + if (!mountedRef.current) return; + if (res.isSuccess && res.isDataAvailable) { + setValue(res.data.value); + setTimestamp(res.data.timestamp); + } else { + setValue(null); + setError(res.error?.errorMessage ?? "No data available"); + } + } catch (err) { + if (!mountedRef.current) return; + setValue(null); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + useEffect(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + setDynamicProps(onDataChange(value != null && timestamp != null ? { + value, + timestamp + } : null) ?? {}); + }, [ + value, + timestamp, + onDataChange + ]); + const resolvedProps = { + title, + unit, + decimalPlaces, + formatValue, + labelText, + width: width ?? DEFAULT_WIDTH, + height, + minWidth, + maxWidth, + className, + theme, + ...dynamicProps, + styles: { + ...styles ?? {}, + ...dynamicProps.styles ?? {} + } + }; + const resolvedTheme = resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" ? lightTheme : resolvedProps.theme ?? lightTheme; + const resolveSlot = (slot) => twMerge(CARD_DEFAULT_CLASSES[slot], resolvedTheme.styles[slot], resolvedProps.styles[slot]); + const displayValue = useMemo(() => { + if (value == null) return null; + if (resolvedProps.formatValue) return resolvedProps.formatValue(value); + if (resolvedProps.decimalPlaces != null) return value.toFixed(resolvedProps.decimalPlaces); + return String(value); + }, [ + value, + resolvedProps.formatValue, + resolvedProps.decimalPlaces + ]); + const displayLabel = useMemo(() => { + if (timestamp == null) return null; + if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); + return `Updated ${(timestamp < 0xe8d4a51000 ? /* @__PURE__ */ new Date(timestamp * 1e3) : new Date(timestamp)).toLocaleTimeString()}`; + }, [timestamp, resolvedProps.labelText]); + const hasExplicitHeight = height != null || dynamicProps.height != null; + return /* @__PURE__ */ jsx("div", { + className: "anedya-card-container", + style: { + width: resolvedProps.width, + minWidth: resolvedProps.minWidth, + maxWidth: resolvedProps.maxWidth, + ...hasExplicitHeight ? { height: resolvedProps.height } : { minHeight: DEFAULT_HEIGHT }, + boxSizing: "border-box", + display: "flex", + flexDirection: "column" + }, + children: /* @__PURE__ */ jsxs("div", { + className: twMerge("anedya-card", resolveSlot("container"), resolvedProps.className), + style: { + flex: "1 0 auto", + ...hasExplicitHeight ? { overflow: "hidden" } : {} + }, + children: [/* @__PURE__ */ jsx("span", { + className: resolveSlot("title"), + children: resolvedProps.title + }), loading ? /* @__PURE__ */ jsxs("div", { + className: "flex flex-col gap-[var(--anedya-card-gap)] w-full items-center justify-center", + children: [/* @__PURE__ */ jsx("div", { + className: "w-2/3 bg-slate-200 dark:bg-slate-700 rounded-md animate-pulse", + style: { + height: "var(--anedya-card-value-size)", + backgroundColor: theme === "dark" ? "#374151" : "#e5e7eb" + } + }), /* @__PURE__ */ jsx("div", { + className: "w-1/2 bg-slate-200 dark:bg-slate-700 rounded-md animate-pulse", + style: { + height: "var(--anedya-card-label-size)", + backgroundColor: theme === "dark" ? "#374151" : "#e5e7eb" + } + })] + }) : error ? /* @__PURE__ */ jsx("span", { + className: "text-red-600 text-sm", + children: error + }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", { + className: twMerge("inline-flex items-baseline justify-center gap-1", resolveSlot("value")), + children: [/* @__PURE__ */ jsx("span", { + className: "min-w-0 break-words", + children: displayValue + }), resolvedProps.unit && /* @__PURE__ */ jsx("span", { + className: resolveSlot("unit"), + children: resolvedProps.unit + })] + }), displayLabel && /* @__PURE__ */ jsx("span", { + className: resolveSlot("label"), + children: displayLabel + })] })] + }) + }); +} +//#endregion +export { CardWidget }; diff --git a/dist/style.css b/dist/style.css deleted file mode 100644 index f50342b9..00000000 --- a/dist/style.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.relative{position:relative}.static{position:static}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.contents{display:contents}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}@media (min-width:40rem){.sm\:text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:64rem){.lg\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card-container{container:anedya-card/inline-size}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem}@container anedya-card (min-width:320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card (min-width:420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 22e7fccb..74010a8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,10 +18,12 @@ "devDependencies": { "@base-ui/react": "^1.6.0", "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", - "tsup": "^8.5.1", + "tsdown": "^0.22.13", "typescript": "^5.7.3" }, "peerDependencies": { @@ -189,446 +191,38 @@ "win32" ] }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", - "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", - "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", - "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", - "cpu": [ - "arm64" - ], + "node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", - "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", - "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", - "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", - "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", - "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", - "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", - "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", - "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", - "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", - "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", - "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", - "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", - "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", - "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", - "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", - "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", - "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", - "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", - "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", - "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", - "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", - "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", - "cpu": [ - "ia32" - ], + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", - "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", - "cpu": [ - "x64" - ], + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@floating-ui/core": { @@ -723,6 +317,35 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", + "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@parcel/watcher": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", @@ -1032,24 +655,23 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", - "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", - "cpu": [ - "arm" - ], + "node_modules/@quansync/fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-1.0.0.tgz", + "integrity": "sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", - "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", + "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", "cpu": [ "arm64" ], @@ -1058,12 +680,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", - "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", "cpu": [ "arm64" ], @@ -1072,12 +697,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", - "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", + "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", "cpu": [ "x64" ], @@ -1086,26 +714,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", - "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", - "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", + "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", "cpu": [ "x64" ], @@ -1114,180 +731,100 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", - "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", - "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", - "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", - "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", - "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", - "cpu": [ - "loong64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", - "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", - "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", - "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", "cpu": [ - "ppc64" + "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", - "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", - "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", - "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", + "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", "cpu": [ - "s390x" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", - "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", + "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", "cpu": [ - "x64" + "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", - "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", "cpu": [ "x64" ], @@ -1296,12 +833,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", - "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", "cpu": [ "x64" ], @@ -1309,13 +849,16 @@ "license": "MIT", "optional": true, "os": [ - "openbsd" - ] + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", - "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", + "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", "cpu": [ "arm64" ], @@ -1324,40 +867,51 @@ "optional": true, "os": [ "openharmony" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", - "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", + "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", "cpu": [ - "arm64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", - "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", + "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", - "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", "cpu": [ "x64" ], @@ -1366,21 +920,17 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", - "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", - "cpu": [ - "x64" ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, "node_modules/@tailwindcss/cli": { "version": "4.3.3", @@ -1658,6 +1208,17 @@ "node": ">= 20" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", @@ -1839,123 +1400,429 @@ "license": "MIT" }, "node_modules/@types/d3-random": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", - "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.4.tgz", + "integrity": "sha512-UHYId5WTCx4L4YNel7NU00XUXXgvgpgZOvp10PuvsQENjMDXhh2RyFc0KBjO7B45ne4Ha1yVH7ii0vnzKkuzWA==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@yuku-codegen/binding-darwin-arm64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-darwin-arm64/-/binding-darwin-arm64-0.7.4.tgz", + "integrity": "sha512-fjkATm+fg4r6Ss8o82u3j33PfIqhSs4A0WEEw9kOwhMx/ui/RQ0ZAsCtF6e7UG2CWGOGXAJspLlfk2tr3rjjKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-codegen/binding-darwin-x64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-darwin-x64/-/binding-darwin-x64-0.7.4.tgz", + "integrity": "sha512-Hj0KvHpS1RJY/bgM3BADzmXXkKO3+bq3M8bMq4b0j0LsVi1SeWYpD/hJLJFwHeNMS+jO4vlZ343yjb4DEb9XXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-codegen/binding-freebsd-x64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-freebsd-x64/-/binding-freebsd-x64-0.7.4.tgz", + "integrity": "sha512-GLKBZvqVFvC1bvNPoPZRj0UxUaAZZKCzb8IPNyvRhXesOk+Af9UbhbVPwx9Do4o2AVf6R5FPzyRWWIihQdCp+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm-gnu": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.7.4.tgz", + "integrity": "sha512-CAjbJexBJUqHgIPgOCJO7EYRnFluNLt5VD3jNS40wmsNZqa04HbewVVcgfmzfzuBhjX6ookntLDG3lWieyTAVw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm-musl": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm-musl/-/binding-linux-arm-musl-0.7.4.tgz", + "integrity": "sha512-HQMuKBltnKFUqhUh8wNiivd76coRwDngdCxbcAULlatAlc2OXo8L6jLTkVnNeUuOw9JYzSq9LY2/7zvrg63Ddg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm64-gnu": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.7.4.tgz", + "integrity": "sha512-cnU7ZVxK/Oq/TIS2iq56rouy1dqnLYgWR2puWcrxGCtmbdxiMISANYhI5t2tMLzTGZMyhawM2zYlyI+gnpBupQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm64-musl": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.7.4.tgz", + "integrity": "sha512-NyuabTumcxPtZv/Q+pMVvrcKxLn1SPcpdBGtekVJz7JwI36SuExTq4IG4EZsk7YDmFKP8wDEvmKYOpV/a8Lwhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-x64-gnu": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.7.4.tgz", + "integrity": "sha512-w3EnCLPD2vpJw0F+0qVV/1KSOAw4SgzjbGUbbwXUh9w5Kxo1Hdc3mN+/Nvk50oA6cCbSOCEaILnPHXPCauArvg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-x64-musl": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-x64-musl/-/binding-linux-x64-musl-0.7.4.tgz", + "integrity": "sha512-FXKQlFjDM8FxqJ/TncAni7e7JyaXIB3Hv6boApxSs5ZUlvqP4TbrjYVk3mYDQt6xQAE/kEHplxM6m5SKx5sfRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-win32-arm64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-win32-arm64/-/binding-win32-arm64-0.7.4.tgz", + "integrity": "sha512-rWr899KEvZIWMx9yUXQl4i90OGIs4gaw4X1UsS2rxsI3qnp8acLIVKI3N5WDqaertkW10crDRZvIxxyw7kTMTQ==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@types/d3-scale-chromatic": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", - "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", - "license": "MIT" + "node_modules/@yuku-codegen/binding-win32-x64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-win32-x64/-/binding-win32-x64-0.7.4.tgz", + "integrity": "sha512-3Olgmkd5rDrIN9g7wJFMRRC9jub5zAwiQOtwOVhvNe/nZE/rSufFRa7vrFupqSCQml+Zxbcy9npzo3Qne3rA2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@types/d3-selection": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", - "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", - "license": "MIT" + "node_modules/@yuku-parser/binding-darwin-arm64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.7.4.tgz", + "integrity": "sha512-rUetRGukIlPOkDCy+Fo0YTee66n9A04XRQMONptbemWSU27CCV6RDj56+4ne4eSE4gJ0139RWUfbqMtt744pWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "node_modules/@yuku-parser/binding-darwin-x64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-darwin-x64/-/binding-darwin-x64-0.7.4.tgz", + "integrity": "sha512-9bHrGQUot2vWTg0YTdyIBHGd38fy2BSQH1WaqUDVuNqSn7HffrTUzWOgbaWRNd5GTOvDdrt9SDZIG7nfqzeBtg==", + "cpu": [ + "x64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" + "node_modules/@yuku-parser/binding-freebsd-x64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.7.4.tgz", + "integrity": "sha512-159565OJ/LR6cCP781nH8DxB5GqlqqWk3uyOLZIznQhsj9zeht4X7+jz9IQH1l/TUio+ojEXf8yt2+DJrN+QVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@types/d3-time-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", - "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", - "license": "MIT" + "node_modules/@yuku-parser/binding-linux-arm-gnu": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.7.4.tgz", + "integrity": "sha512-j3s3LJxEbOyP58hmzuXpJlKzgxaswuOTu8nAbDpE119b5W3gP1SW+HndLscGUOACpyMdH5WJ6gBHRxq0HCRVBw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" + "node_modules/@yuku-parser/binding-linux-arm-musl": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm-musl/-/binding-linux-arm-musl-0.7.4.tgz", + "integrity": "sha512-PUpHPmvWIDxhYTS5oah08RQ28t6dlFBxRPJcftS6HgquiPsm/e0gL5vKwPJpyjaPBHzRH61IAUDDfrRe8iFs8g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-transition": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", - "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "node_modules/@yuku-parser/binding-linux-arm64-gnu": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.7.4.tgz", + "integrity": "sha512-Hi3w0et5mu3i7S+qE0UgOev4RqJ/U9DW8xn79t4nttiICYCx3NveC0Goo78uqzxttsDI3hfRY43lrrF26svqcw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-selection": "*" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/d3-zoom": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", - "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "node_modules/@yuku-parser/binding-linux-arm64-musl": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.7.4.tgz", + "integrity": "sha512-i073u4ENL9DJeWBRKioRCz8i5hg6EmUcH89eH1lts9f9AFPA1GphODwK6OXOXUbpi2AwZ1deFIUWgLGP2mdmmA==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "node_modules/@yuku-parser/binding-linux-x64-gnu": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.7.4.tgz", + "integrity": "sha512-j5pt0LyDGxCzfoqRTR3cmMG21+bgSxIufAzJXFOWXkbg/22Ih51eGEsbInnSD5Q9FvJ3ooIn/jfok0dBdhudnA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" + "node_modules/@yuku-parser/binding-linux-x64-musl": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.7.4.tgz", + "integrity": "sha512-RR1hNhrSpv3FanLM6u5uD+9CYA9IM8U3uGscgvKKV77gtj7ttO4UubpwN7vcx1KknoEIQHKJFPVKoeVy+avf6w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "node_modules/@yuku-parser/binding-win32-arm64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-win32-arm64/-/binding-win32-arm64-0.7.4.tgz", + "integrity": "sha512-1xhYwOLo9TjppHHwNYi3X/dGgOvnj9xh62jpgP4U8nEtTGA70NtJDCkN45pRQdU3B6/U7oQj1T4esP3aFJg6BA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } + "os": [ + "win32" + ] }, - "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "node_modules/@yuku-parser/binding-win32-x64": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-win32-x64/-/binding-win32-x64-0.7.4.tgz", + "integrity": "sha512-HonZAapmSKusxLZPnU9WrMzAUdPSBJliGw3CSkA9Er/aq15STEOEy9SOsVGvj4maBv95EmWxt2LThHXnFnGfNg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "node_modules/@yuku-toolchain/types": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@yuku-toolchain/types/-/types-0.7.4.tgz", + "integrity": "sha512-iUFXr+UnUJjzVLNI6GIv07poi9NwcG5hTBJSheJh3SdpkYpIjCl9kAGe7dbJMHn5sXeceCL4H12pKa0b6pkouQ==", "dev": true, "license": "MIT" }, + "node_modules/ansis": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", + "integrity": "sha512-BJ8/l4R5LRE7hW9WdSuGYrLSHi2ynxeFpDFbH0K/CgNeY/tyhk+vO6TYxXC5r5CpUhNVX310xzPsN/H9lCdfOA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -1969,30 +1836,14 @@ "node": ">=8" } }, - "node_modules/bundle-require": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", - "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "load-tsconfig": "^0.2.3" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "esbuild": ">=0.18" - } - }, "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cac/-/cac-7.0.0.tgz", + "integrity": "sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=20.19.0" } }, "node_modules/cbor-extract": { @@ -2026,22 +1877,6 @@ "cbor-extract": "^2.2.2" } }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -2060,31 +1895,12 @@ "node": ">= 10" } }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/d3": { "version": "7.9.0", @@ -2487,23 +2303,12 @@ "node": ">=12" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } + "license": "MIT" }, "node_modules/delaunator": { "version": "5.1.0", @@ -2527,6 +2332,37 @@ "node": ">=0.10" } }, + "node_modules/dts-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-3.0.0.tgz", + "integrity": "sha512-1T1f+z+4tl9XD+m+0HBgWoL/nm0bOIffyWaUuUSBlFg/86IWvfx+wjNaO/ybU0AJzG9/Mi5hBUgGV6zCmWEN7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "oxc-resolver": ">=11.0.0" + }, + "peerDependenciesMeta": { + "oxc-resolver": { + "optional": true + } + } + }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/enhanced-resolve": { "version": "5.24.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", @@ -2541,46 +2377,22 @@ "node": ">=10.13.0" } }, - "node_modules/esbuild": { - "version": "0.27.7", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", - "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, "engines": { - "node": ">=18" + "node": ">=12.0.0" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.7", - "@esbuild/android-arm": "0.27.7", - "@esbuild/android-arm64": "0.27.7", - "@esbuild/android-x64": "0.27.7", - "@esbuild/darwin-arm64": "0.27.7", - "@esbuild/darwin-x64": "0.27.7", - "@esbuild/freebsd-arm64": "0.27.7", - "@esbuild/freebsd-x64": "0.27.7", - "@esbuild/linux-arm": "0.27.7", - "@esbuild/linux-arm64": "0.27.7", - "@esbuild/linux-ia32": "0.27.7", - "@esbuild/linux-loong64": "0.27.7", - "@esbuild/linux-mips64el": "0.27.7", - "@esbuild/linux-ppc64": "0.27.7", - "@esbuild/linux-riscv64": "0.27.7", - "@esbuild/linux-s390x": "0.27.7", - "@esbuild/linux-x64": "0.27.7", - "@esbuild/netbsd-arm64": "0.27.7", - "@esbuild/netbsd-x64": "0.27.7", - "@esbuild/openbsd-arm64": "0.27.7", - "@esbuild/openbsd-x64": "0.27.7", - "@esbuild/openharmony-arm64": "0.27.7", - "@esbuild/sunos-x64": "0.27.7", - "@esbuild/win32-arm64": "0.27.7", - "@esbuild/win32-ia32": "0.27.7", - "@esbuild/win32-x64": "0.27.7" + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/fill-range": { @@ -2596,31 +2408,20 @@ "node": ">=8" } }, - "node_modules/fix-dts-default-cjs-exports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", - "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", + "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", "dev": true, "license": "MIT", "dependencies": { - "magic-string": "^0.30.17", - "mlly": "^1.7.4", - "rollup": "^4.34.8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "resolve-pkg-maps": "^1.0.0" + }, "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">=20.20.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, "node_modules/graceful-fs": { @@ -2630,6 +2431,13 @@ "dev": true, "license": "ISC" }, + "node_modules/hookable": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-6.1.1.tgz", + "integrity": "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==", + "dev": true, + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -2642,6 +2450,19 @@ "node": ">=0.10.0" } }, + "node_modules/import-without-cache": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/import-without-cache/-/import-without-cache-0.4.0.tgz", + "integrity": "sha512-NkJQA7oZ4YHQhd2+H3BoRFKF3d/XNsiKpHZCQEMH9pDX27hQQLsTyOocyRgaIVtf8gHX3Nt3LPkR4e5EdtPAGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^22.18.0 || >=24.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/internmap": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", @@ -2694,16 +2515,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -2975,36 +2786,6 @@ "node": ">=8" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -3029,19 +2810,6 @@ "node": ">=8.6" } }, - "node_modules/mlly": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", - "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.16.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.3" - } - }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -3052,25 +2820,6 @@ "node": ">=4" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -3103,23 +2852,20 @@ "node": ">=8" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12.20.0" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -3140,75 +2886,27 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "node_modules/quansync": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", + "integrity": "sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==", "dev": true, "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "type": "individual", + "url": "https://github.com/sponsors/antfu" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "individual", + "url": "https://github.com/sponsors/sxzz" } ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } + "license": "MIT" }, "node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "dev": true, "license": "MIT", "engines": { @@ -3216,30 +2914,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.7" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "react": "^19.2.8" } }, "node_modules/reselect": { @@ -3249,14 +2933,14 @@ "dev": true, "license": "MIT" }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, "node_modules/robust-predicates": { @@ -3265,49 +2949,80 @@ "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", "license": "Unlicense" }, - "node_modules/rollup": { - "version": "4.62.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", - "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", + "node_modules/rolldown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", + "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.9" + "@oxc-project/types": "=0.140.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.2", - "@rollup/rollup-android-arm64": "4.62.2", - "@rollup/rollup-darwin-arm64": "4.62.2", - "@rollup/rollup-darwin-x64": "4.62.2", - "@rollup/rollup-freebsd-arm64": "4.62.2", - "@rollup/rollup-freebsd-x64": "4.62.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", - "@rollup/rollup-linux-arm-musleabihf": "4.62.2", - "@rollup/rollup-linux-arm64-gnu": "4.62.2", - "@rollup/rollup-linux-arm64-musl": "4.62.2", - "@rollup/rollup-linux-loong64-gnu": "4.62.2", - "@rollup/rollup-linux-loong64-musl": "4.62.2", - "@rollup/rollup-linux-ppc64-gnu": "4.62.2", - "@rollup/rollup-linux-ppc64-musl": "4.62.2", - "@rollup/rollup-linux-riscv64-gnu": "4.62.2", - "@rollup/rollup-linux-riscv64-musl": "4.62.2", - "@rollup/rollup-linux-s390x-gnu": "4.62.2", - "@rollup/rollup-linux-x64-gnu": "4.62.2", - "@rollup/rollup-linux-x64-musl": "4.62.2", - "@rollup/rollup-openbsd-x64": "4.62.2", - "@rollup/rollup-openharmony-arm64": "4.62.2", - "@rollup/rollup-win32-arm64-msvc": "4.62.2", - "@rollup/rollup-win32-ia32-msvc": "4.62.2", - "@rollup/rollup-win32-x64-gnu": "4.62.2", - "@rollup/rollup-win32-x64-msvc": "4.62.2", - "fsevents": "~2.3.2" + "@rolldown/binding-android-arm64": "1.2.0", + "@rolldown/binding-darwin-arm64": "1.2.0", + "@rolldown/binding-darwin-x64": "1.2.0", + "@rolldown/binding-freebsd-x64": "1.2.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", + "@rolldown/binding-linux-arm64-gnu": "1.2.0", + "@rolldown/binding-linux-arm64-musl": "1.2.0", + "@rolldown/binding-linux-ppc64-gnu": "1.2.0", + "@rolldown/binding-linux-s390x-gnu": "1.2.0", + "@rolldown/binding-linux-x64-gnu": "1.2.0", + "@rolldown/binding-linux-x64-musl": "1.2.0", + "@rolldown/binding-openharmony-arm64": "1.2.0", + "@rolldown/binding-wasm32-wasi": "1.2.0", + "@rolldown/binding-win32-arm64-msvc": "1.2.0", + "@rolldown/binding-win32-x64-msvc": "1.2.0" + } + }, + "node_modules/rolldown-plugin-dts": { + "version": "0.27.13", + "resolved": "https://registry.npmjs.org/rolldown-plugin-dts/-/rolldown-plugin-dts-0.27.13.tgz", + "integrity": "sha512-DeVZJbbB0ajp5q6vABqC8ZCJzxftlxbiV60Bk96GFdQaysGVpgTTVjQu0lUt4Lb+aRCtejfOixtQKDRol7IuVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dts-resolver": "^3.0.0", + "get-tsconfig": "5.0.0-beta.5", + "obug": "^2.1.4", + "yuku-ast": "^0.7.0", + "yuku-codegen": "^0.7.0", + "yuku-parser": "^0.7.0" + }, + "engines": { + "node": "^22.18.0 || >=24.11.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@typescript/native-preview": "*", + "@volar/typescript": "~2.4.0", + "rolldown": "^1.0.0", + "typescript": "^5.0.0 || ^6.0.0 || ~7.0.0", + "vue-tsc": "~3.2.0 || ~3.3.0" + }, + "peerDependenciesMeta": { + "@typescript/native-preview": { + "optional": true + }, + "@volar/typescript": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } } }, "node_modules/rw": { @@ -3329,16 +3044,6 @@ "dev": true, "license": "MIT" }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3349,39 +3054,6 @@ "node": ">=0.10.0" } }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/tailwind-merge": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", @@ -3413,36 +3085,16 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, "engines": { - "node": ">=0.8" + "node": ">=18" } }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -3460,24 +3112,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/tinyglobby/node_modules/picomatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", @@ -3514,70 +3148,104 @@ "tree-kill": "cli.js" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/tsup": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", - "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", + "node_modules/tsdown": { + "version": "0.22.13", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.22.13.tgz", + "integrity": "sha512-XaYFhtiKRUvTpXv/YAehsHdbEb3LN/iMlzjSINbjlaATtXN2zVPKox2STKhcyFPlh++8Zg7suNN27E679IfAUA==", "dev": true, "license": "MIT", "dependencies": { - "bundle-require": "^5.1.0", - "cac": "^6.7.14", - "chokidar": "^4.0.3", - "consola": "^3.4.0", - "debug": "^4.4.0", - "esbuild": "^0.27.0", - "fix-dts-default-cjs-exports": "^1.0.0", - "joycon": "^3.1.1", - "picocolors": "^1.1.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.34.8", - "source-map": "^0.7.6", - "sucrase": "^3.35.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.11", - "tree-kill": "^1.2.2" + "ansis": "^4.3.1", + "cac": "^7.0.0", + "defu": "^6.1.7", + "empathic": "^2.0.1", + "hookable": "^6.1.1", + "import-without-cache": "^0.4.0", + "obug": "^2.1.4", + "picomatch": "^4.0.5", + "rolldown": "~1.2.0", + "rolldown-plugin-dts": "^0.27.12", + "tinyexec": "^1.2.4", + "tinyglobby": "^0.2.17", + "tree-kill": "^1.2.2", + "unconfig-core": "^7.5.0", + "verkit": "^0.1.2" }, "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" + "tsdown": "dist/run.mjs" }, "engines": { - "node": ">=18" + "node": "^22.18.0 || >=24.11.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" }, "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" + "@arethetypeswrong/core": "^0.18.1", + "@tsdown/css": "0.22.13", + "@tsdown/exe": "0.22.13", + "@vitejs/devtools": "*", + "publint": "^0.3.8", + "tsx": "*", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0", + "unplugin-unused": "^0.5.0", + "unrun": "*" }, "peerDependenciesMeta": { - "@microsoft/api-extractor": { + "@arethetypeswrong/core": { + "optional": true + }, + "@tsdown/css": { "optional": true }, - "@swc/core": { + "@tsdown/exe": { "optional": true }, - "postcss": { + "@vitejs/devtools": { + "optional": true + }, + "publint": { + "optional": true + }, + "tsx": { "optional": true }, "typescript": { "optional": true + }, + "unplugin-unused": { + "optional": true + }, + "unrun": { + "optional": true } } }, + "node_modules/tsdown/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3588,12 +3256,19 @@ "node": ">=14.17" } }, - "node_modules/ufo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "node_modules/unconfig-core": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/unconfig-core/-/unconfig-core-7.5.0.tgz", + "integrity": "sha512-Su3FauozOGP44ZmKdHy2oE6LPjk51M/TRRjHv2HNCWiDvfvCoxC2lno6jevMA91MYAdCdwP05QnWdWpSbncX/w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@quansync/fs": "^1.0.0", + "quansync": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } }, "node_modules/use-sync-external-store": { "version": "1.6.0", @@ -3604,6 +3279,76 @@ "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } + }, + "node_modules/verkit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.1.2.tgz", + "integrity": "sha512-WqkT8n3hqizuCu71W3bUzf5fjBmkbXcudsehe/NbxA8PgqoKnSOY5K0Ba2ckg1qaRaSpSz7as/n9K1R9JXjQKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/yuku-ast": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/yuku-ast/-/yuku-ast-0.7.4.tgz", + "integrity": "sha512-Pn6e7uZOBczeJ+JIiPGtD4aw6eRflzKrZJmAdeg092RxM9tQtvAkZAbEoknNgYmsB6dGYESvXPQcUE7Nu8ai7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yuku-toolchain/types": "^0.7.4" + } + }, + "node_modules/yuku-codegen": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/yuku-codegen/-/yuku-codegen-0.7.4.tgz", + "integrity": "sha512-bLdC5yzvn507PtU7+kB4CMBLfnvKW1N2m26Vpl1q4Os+FLROnkKTThM7g+clVb+9tHaOlcc6gqQ+rNBY8L/Dxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yuku-toolchain/types": "^0.7.4" + }, + "optionalDependencies": { + "@yuku-codegen/binding-darwin-arm64": "0.7.4", + "@yuku-codegen/binding-darwin-x64": "0.7.4", + "@yuku-codegen/binding-freebsd-x64": "0.7.4", + "@yuku-codegen/binding-linux-arm-gnu": "0.7.4", + "@yuku-codegen/binding-linux-arm-musl": "0.7.4", + "@yuku-codegen/binding-linux-arm64-gnu": "0.7.4", + "@yuku-codegen/binding-linux-arm64-musl": "0.7.4", + "@yuku-codegen/binding-linux-x64-gnu": "0.7.4", + "@yuku-codegen/binding-linux-x64-musl": "0.7.4", + "@yuku-codegen/binding-win32-arm64": "0.7.4", + "@yuku-codegen/binding-win32-x64": "0.7.4" + } + }, + "node_modules/yuku-parser": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/yuku-parser/-/yuku-parser-0.7.4.tgz", + "integrity": "sha512-HveMyhZPQQfR4z3xskXv5hHJW9g0KIESZW6JvUZv7Jn52FfMFUhCYL77KHBtnWGFti0KrKeTHMZVTY5AUVgFAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yuku-toolchain/types": "^0.7.4", + "yuku-ast": "^0.7.4" + }, + "optionalDependencies": { + "@yuku-parser/binding-darwin-arm64": "0.7.4", + "@yuku-parser/binding-darwin-x64": "0.7.4", + "@yuku-parser/binding-freebsd-x64": "0.7.4", + "@yuku-parser/binding-linux-arm-gnu": "0.7.4", + "@yuku-parser/binding-linux-arm-musl": "0.7.4", + "@yuku-parser/binding-linux-arm64-gnu": "0.7.4", + "@yuku-parser/binding-linux-arm64-musl": "0.7.4", + "@yuku-parser/binding-linux-x64-gnu": "0.7.4", + "@yuku-parser/binding-linux-x64-musl": "0.7.4", + "@yuku-parser/binding-win32-arm64": "0.7.4", + "@yuku-parser/binding-win32-x64": "0.7.4" + } } } } diff --git a/package.json b/package.json index e3ade950..94a76f88 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Anedya widget SDK", "main": "dist/index.js", "module": "dist/index.mjs", + "type": "module", "types": "dist/index.d.ts", "files": [ "dist" @@ -15,13 +16,15 @@ }, "./styles.css": "./dist/styles.css" }, - "scripts": { - "clean": "rm -rf dist", - "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify", - "build:js": "tsup", +"scripts": { + "clean": "rm -rf dist", +"build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/styles.css --minify", + "build:js": "tsdown", "build": "npm run clean && npm run build:js && npm run build:css", - "typecheck": "tsc --noEmit" - }, + "dev": "npm run clean && tsdown --watch", + "typecheck": "tsc --noEmit" +}, + "repository": { "type": "git", "url": "git@github.com:abhishreecodes/new-sdk.git" @@ -45,10 +48,12 @@ "devDependencies": { "@base-ui/react": "^1.6.0", "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwindcss": "^4.3.2", - "tsup": "^8.5.1", + "tsdown": "^0.22.13", "typescript": "^5.7.3" } } diff --git a/public-widget-sdk@5.5.0 b/public-widget-sdk@5.5.0 deleted file mode 100644 index e69de29b..00000000 diff --git a/rollup b/rollup deleted file mode 100644 index e69de29b..00000000 diff --git a/src/common.ts b/src/common.ts index 44dfee98..9a5581e8 100644 --- a/src/common.ts +++ b/src/common.ts @@ -5,7 +5,7 @@ import { WidgetTheme } from "./types/root"; /** * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this + * (e.g. Card's `unit`/`decimalPlaces`, Chart's `tickCount`) extend this * rather than repeating client/node/sizing/theme plumbing per widget. * * `node` is required directly (built by the consumer via @@ -27,7 +27,7 @@ export interface AnedyaWidgetBaseProps { * * A theme is a reusable collection of classes for the widget's slots. * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. + * `styles` prop is applied afterwards for per-instance overrides. */ theme?: WidgetTheme | BuiltInTheme; @@ -38,6 +38,11 @@ theme?: WidgetTheme | BuiltInTheme; // Sizing β€” stay as direct props (shorthand for the container's // width/height), matching the existing ChartWidget convention. width?: number; + /** + * Card height in pixels. + * - If provided: treated as a fixed size. Content that doesn't fit will be clipped. + * - If omitted: the card grows to fit its content naturally. + */ height?: number; minWidth?: number; maxWidth?: number; diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 49de2379..4b0b0238 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -25,7 +25,7 @@ export type CardWidgetUpdate = Partial< export interface CardWidgetProps extends AnedyaWidgetBaseProps { unit?: string; /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; + decimalPlaces?: number; formatValue?: (value: number) => string; /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ labelText?: (timestamp: number) => string; @@ -38,7 +38,7 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * Tailwind conflicts are resolved via `twMerge`, so later overrides * replace earlier utilities within the same Tailwind class group. */ - classNames?: SlotClassNames; + styles?: SlotClassNames; /** * Called whenever the latest fetched data changes. * @@ -60,7 +60,7 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * return { * title: "High Humidity", * theme: "dark", - * classNames: { + * styles: { * value: "text-red-500", * }, * }; @@ -71,6 +71,7 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { } const DEFAULT_WIDTH = 240; +const DEFAULT_HEIGHT = 160; const DEFAULT_MIN_WIDTH = 180; const DEFAULT_MAX_WIDTH = 480; @@ -79,10 +80,10 @@ export function CardWidget({ variable, title = "Latest Value", unit, - precision, + decimalPlaces, formatValue, labelText, - classNames = {}, + styles = {}, onDataChange, theme, className, @@ -91,7 +92,7 @@ export function CardWidget({ height, minWidth = DEFAULT_MIN_WIDTH, maxWidth = DEFAULT_MAX_WIDTH, -}: CardWidgetProps) { +}: CardWidgetProps): React.JSX.Element { const [value, setValue] = useState(null); const [timestamp, setTimestamp] = useState(null); const [loading, setLoading] = useState(false); @@ -162,20 +163,21 @@ export function CardWidget({ const resolvedProps = { title, unit, - precision, + decimalPlaces, formatValue, labelText, width: width ?? DEFAULT_WIDTH, - height, +// height: height ?? DEFAULT_HEIGHT, +height, minWidth, maxWidth, className, theme, ...dynamicProps, - classNames: { - ...(classNames ?? {}), - ...(dynamicProps.classNames ?? {}), + styles: { + ...(styles ?? {}), + ...(dynamicProps.styles ?? {}), }, }; @@ -188,17 +190,17 @@ export function CardWidget({ // Per-slot resolution, lowest to highest precedence: // 1. CARD_DEFAULT_CLASSES[slot] β€” built-in baseline - // 2. resolvedTheme.classNames[slot] β€” active theme's classes - // 3. resolvedProps.classNames - // (original classNames merged with any returned by onDataChange) + // 2. resolvedTheme.styles[slot] β€” active theme's classes + // 3. resolvedProps.styles + // (original styles merged with any returned by onDataChange) // twMerge resolves any real Tailwind conflicts between these layers // based on actual utility groups, not the order they're written in. const resolveSlot = (slot: CardSlot) => twMerge( CARD_DEFAULT_CLASSES[slot], - resolvedTheme.classNames[slot], - resolvedProps.classNames[slot], + resolvedTheme.styles[slot], + resolvedProps.styles[slot], ); const displayValue = useMemo(() => { @@ -206,11 +208,11 @@ export function CardWidget({ if (resolvedProps.formatValue) return resolvedProps.formatValue(value); - if (resolvedProps.precision != null) - return value.toFixed(resolvedProps.precision); + if (resolvedProps.decimalPlaces != null) + return value.toFixed(resolvedProps.decimalPlaces); return String(value); - }, [value, resolvedProps.formatValue, resolvedProps.precision]); + }, [value, resolvedProps.formatValue, resolvedProps.decimalPlaces]); const displayLabel = useMemo(() => { if (timestamp == null) return null; @@ -221,6 +223,9 @@ export function CardWidget({ return `Updated ${d.toLocaleTimeString()}`; }, [timestamp, resolvedProps.labelText]); + + const hasExplicitHeight = height != null || dynamicProps.height != null; + return (
@@ -246,39 +254,31 @@ export function CardWidget({ {loading ? ( -
- -
+
+ {/* Value Skeleton: Uses the exact font-size variable as its height */} +
+ + {/* Label Skeleton: Uses the exact label-size variable as its height */} +
+
) : error ? ( {error} ) : ( <> - {/* - {displayValue} - {resolvedProps.unit && ( - - {resolvedProps.unit} - - )} - */} - - {displayValue} + {displayValue} {resolvedProps.unit && ( diff --git a/src/styles/base.css b/src/styles/base.css index 53a4292d..907aa86f 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -1,52 +1,26 @@ @import "tailwindcss"; -/* Explicit @source directives, so Tailwind scans exactly the folders - that actually contain our class strings (CARD_DEFAULT_CLASSES, - lightTheme, darkTheme, and any future widget's defaults), rather - than relying purely on automatic content detection. Paths are - relative to THIS file's location (src/styles/base.css). */ @source "../widgets/**/*.{ts,tsx}"; @source "../themes/**/*.{ts,tsx}"; @source "../common.ts"; -/* ---------- Widget defaults ---------- */ .anedya-card-container { - container-type: inline-size; + container-type: size; container-name: anedya-card; + transition: width 0.25s ease, height 0.25s ease; } - .anedya-card { - --anedya-card-padding: 1rem; - --anedya-card-title-size: .875rem; - --anedya-card-value-size: 2.25rem; - --anedya-card-unit-size: 1rem; - --anedya-card-label-size: .75rem; - --anedya-card-gap: .5rem; -} - -@container anedya-card (min-width: 320px) { - .anedya-card { - --anedya-card-padding: 1.25rem; - - --anedya-card-title-size: 1rem; - --anedya-card-value-size: 2.75rem; - --anedya-card-unit-size: 1.125rem; - --anedya-card-label-size: 0.875rem; - - --anedya-card-gap: 0.75rem; - } + --anedya-card-padding: clamp(1rem, 0.5rem + 2.5cqw + 2.5cqh, 4.5rem); + --anedya-card-title-size: clamp(0.875rem, 0.6rem + 1.5cqw + 1.5cqh, 3rem); + --anedya-card-value-size: clamp(2.25rem, 1rem + 8cqw + 8cqh, 9.5rem); + --anedya-card-unit-size: clamp(1rem, 0.7rem + 1.5cqw + 1.5cqh, 3.25rem); + --anedya-card-label-size: clamp(0.75rem, 0.5rem + 1.2cqw + 1.2cqh, 2.25rem); + --anedya-card-gap: clamp(0.5rem, 0.2rem + 2cqw + 3cqh, 3.5rem); + + transition: padding 0.25s ease, gap 0.25s ease; } -@container anedya-card (min-width: 420px) { - .anedya-card { - --anedya-card-padding: 1.5rem; - - --anedya-card-title-size: 1.125rem; ---anedya-card-value-size: 5rem; - --anedya-card-unit-size: 1.25rem; - --anedya-card-label-size: 1rem; - - --anedya-card-gap: 1rem; - } -} +.anedya-card > * { + transition: font-size 0.25s ease; +} \ No newline at end of file diff --git a/src/themes/defaultTheme.ts b/src/themes/defaultTheme.ts index 4f4bd20e..da6f9f13 100644 --- a/src/themes/defaultTheme.ts +++ b/src/themes/defaultTheme.ts @@ -7,8 +7,7 @@ export const CARD_DEFAULT_CLASSES: Record = { title: "text-[length:var(--anedya-card-title-size)] font-medium", -value: - "text-[length:var(--anedya-card-value-size)] font-bold", +value: "text-[length:var(--anedya-card-value-size)] font-bold max-w-full min-w-0 leading-tight", unit: "text-[length:var(--anedya-card-unit-size)]", @@ -21,7 +20,7 @@ container: export const lightTheme: WidgetTheme = { - classNames: { + styles: { container: "bg-white border-slate-200", title: "text-slate-500", value: "text-slate-900", @@ -30,7 +29,7 @@ export const lightTheme: WidgetTheme = { }; export const darkTheme: WidgetTheme = { - classNames: { + styles: { container: "bg-slate-900 border-slate-800", title: "text-slate-400", value: "text-white", diff --git a/src/types/root.ts b/src/types/root.ts index 22e111dd..061145ee 100644 --- a/src/types/root.ts +++ b/src/types/root.ts @@ -16,10 +16,10 @@ export type SlotClassNames = * ↓ * user theme * ↓ - * widget classNames prop + * widget styles prop * * Later layers win via `twMerge`. */ export interface WidgetTheme { - classNames: SlotClassNames; + styles: SlotClassNames; } \ No newline at end of file diff --git a/test/my-app/.env.example b/test/my-app/.env.example new file mode 100644 index 00000000..ec1a2dc6 --- /dev/null +++ b/test/my-app/.env.example @@ -0,0 +1,3 @@ +VITE_CARD_WIDGET_TOKEN_ID="your_token_id_here" +VITE_CARD_WIDGET_TOKEN="your_token_secret_here" +VITE_CARD_WIDGET_NODE_ID="your_node_id_here" \ No newline at end of file diff --git a/test/my-app/.gitignore b/test/my-app/.gitignore index a547bf36..7ceb59f8 100644 --- a/test/my-app/.gitignore +++ b/test/my-app/.gitignore @@ -22,3 +22,4 @@ dist-ssr *.njsproj *.sln *.sw? +.env diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index 390f6bfa..a76992ee 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -11,6 +11,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^9.2.0", + "public-widget-sdk": "file:../../", "react": "^19.2.4", "react-dom": "^19.2.4" }, @@ -29,13 +30,44 @@ "vite": "^8.0.1" } }, + "../..": { + "name": "public-widget-sdk", + "version": "5.5.0", + "license": "ISC", + "dependencies": { + "@anedyasystems/anedya-frontend-sdk": "^0.1.1", + "@types/d3": "^7.4.3", + "clsx": "^2.1.1", + "d3": "^7.9.0", + "tailwind-merge": "^3.6.0" + }, + "devDependencies": { + "@base-ui/react": "^1.6.0", + "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.3.2", + "tsdown": "^0.22.13", + "typescript": "^5.7.3" + }, + "peerDependencies": { + "@base-ui/react": "^1.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "../../../../anedya-widgets-react": { + "extraneous": true + }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -44,9 +76,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -54,21 +86,21 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -85,13 +117,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -101,14 +133,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -118,37 +150,37 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -158,27 +190,27 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -186,26 +218,26 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -224,31 +256,31 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -256,35 +288,35 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@emnapi/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.1.tgz", - "integrity": "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", "dev": true, "license": "MIT", "optional": true, "peer": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.1.tgz", - "integrity": "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", "dev": true, "license": "MIT", "optional": true, @@ -294,13 +326,12 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -458,9 +489,9 @@ "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", "dev": true, "license": "MIT", "dependencies": { @@ -541,9 +572,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", "dev": true, "license": "MIT", "dependencies": { @@ -553,7 +584,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", + "js-yaml": "^4.3.0", "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, @@ -578,9 +609,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", "dev": true, "license": "MIT", "engines": { @@ -615,29 +646,43 @@ } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -920,14 +965,14 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.2.tgz", - "integrity": "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.3" }, "funding": { "type": "github", @@ -939,11 +984,12 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.122.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.122.0.tgz", - "integrity": "sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==", + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", + "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/Boshen" } @@ -959,9 +1005,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-pv1y2Fv0JybcykuiiD3qBOBdz6RteYojRFY1d+b95WVuzx211CRh+ytI/+9iVyWQ6koTh5dawe4S/yRfOFjgaA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", + "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", "cpu": [ "arm64" ], @@ -971,14 +1017,15 @@ "os": [ "android" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-cFYr6zTG/3PXXF3pUO+umXxt1wkRK/0AYT8lDwuqvRC+LuKYWSAQAQZjCWDQpAH172ZV6ieYrNnFzVVcnSflAg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", "cpu": [ "arm64" ], @@ -988,14 +1035,15 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-ZCsYknnHzeXYps0lGBz8JrF37GpE9bFVefrlmDrAQhOEi4IOIlcoU1+FwHEtyXGx2VkYAvhu7dyBf75EJQffBw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", + "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", "cpu": [ "x64" ], @@ -1005,14 +1053,15 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.12.tgz", - "integrity": "sha512-dMLeprcVsyJsKolRXyoTH3NL6qtsT0Y2xeuEA8WQJquWFXkEC4bcu1rLZZSnZRMtAqwtrF/Ib9Ddtpa/Gkge9Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", + "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", "cpu": [ "x64" ], @@ -1022,14 +1071,15 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.12.tgz", - "integrity": "sha512-YqWjAgGC/9M1lz3GR1r1rP79nMgo3mQiiA+Hfo+pvKFK1fAJ1bCi0ZQVh8noOqNacuY1qIcfyVfP6HoyBRZ85Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", "cpu": [ "arm" ], @@ -1039,14 +1089,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-/I5AS4cIroLpslsmzXfwbe5OmWvSsrFuEw3mwvbQ1kDxJ822hFHIx+vsN/TAzNVyepI/j/GSzrtCIwQPeKCLIg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", "cpu": [ "arm64" ], @@ -1056,14 +1107,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-V6/wZztnBqlx5hJQqNWwFdxIKN0m38p8Jas+VoSfgH54HSj9tKTt1dZvG6JRHcjh6D7TvrJPWFGaY9UBVOaWPw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", "cpu": [ "arm64" ], @@ -1073,14 +1125,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-AP3E9BpcUYliZCxa3w5Kwj9OtEVDYK6sVoUzy4vTOJsjPOgdaJZKFmN4oOlX0Wp0RPV2ETfmIra9x1xuayFB7g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", + "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", "cpu": [ "ppc64" ], @@ -1090,14 +1143,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-nWwpvUSPkoFmZo0kQazZYOrT7J5DGOJ/+QHHzjvNlooDZED8oH82Yg67HvehPPLAg5fUff7TfWFHQS8IV1n3og==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", + "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", "cpu": [ "s390x" ], @@ -1107,14 +1161,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.12.tgz", - "integrity": "sha512-RNrafz5bcwRy+O9e6P8Z/OCAJW/A+qtBczIqVYwTs14pf4iV1/+eKEjdOUta93q2TsT/FI0XYDP3TCky38LMAg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", "cpu": [ "x64" ], @@ -1124,14 +1179,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.12.tgz", - "integrity": "sha512-Jpw/0iwoKWx3LJ2rc1yjFrj+T7iHZn2JDg1Yny1ma0luviFS4mhAIcd1LFNxK3EYu3DHWCps0ydXQ5i/rrJ2ig==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", "cpu": [ "x64" ], @@ -1141,14 +1197,15 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.12.tgz", - "integrity": "sha512-vRugONE4yMfVn0+7lUKdKvN4D5YusEiPilaoO2sgUWpCvrncvWgPMzK00ZFFJuiPgLwgFNP5eSiUlv2tfc+lpA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", + "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", "cpu": [ "arm64" ], @@ -1158,31 +1215,35 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.12.tgz", - "integrity": "sha512-ykGiLr/6kkiHc0XnBfmFJuCjr5ZYKKofkx+chJWDjitX+KsJuAmrzWhwyOMSHzPhzOHOy7u9HlFoa5MoAOJ/Zg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", + "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", "cpu": [ "wasm32" ], "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-5eOND4duWkwx1AzCxadcOrNeighiLwMInEADT0YM7xeEOOFcovWZCq8dadXgcRHSf3Ulh1kFo/qvzoFiCLOL1Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", + "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", "cpu": [ "arm64" ], @@ -1192,14 +1253,15 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.12.tgz", - "integrity": "sha512-PyqoipaswDLAZtot351MLhrlrh6lcZPo2LSYE+VDxbVk24LVKAGOuE4hb8xZQmrPAuEtTZW8E6D2zc5EUZX4Lw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", "cpu": [ "x64" ], @@ -1209,18 +1271,19 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/plugin-babel": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.2.tgz", - "integrity": "sha512-q9pE8+47bQNHb5eWVcE6oXppA+JTSwvnrhH53m0ZuHuK5MLvwsLoWrWzBTFQqQ06BVxz1gp0HblLsch8o6pvZw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.3.tgz", + "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", "dev": true, "license": "MIT", "dependencies": { - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=22.12.0 || ^24.0.0" @@ -1245,16 +1308,16 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.7", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", - "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "dev": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "dev": true, "license": "MIT", "optional": true, @@ -1263,9 +1326,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -1289,9 +1352,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -1317,13 +1380,13 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", - "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.4.tgz", + "integrity": "sha512-XcCQz0TBpBgljhj0gMuuDj49i6Ytqh5q1osT/Gp5uAVJUCTWxyskk/l1jwYYiu2xcNHHipdMz40EGfM1VdamVg==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.7" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -1343,9 +1406,9 @@ } }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", "bin": { @@ -1366,9 +1429,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1438,9 +1501,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.12", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.12.tgz", - "integrity": "sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==", + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.1.tgz", + "integrity": "sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==", "dev": true, "license": "Apache-2.0", "bin": { @@ -1451,9 +1514,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1462,9 +1525,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", "dev": true, "funding": [ { @@ -1482,10 +1545,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" }, "bin": { @@ -1505,9 +1568,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001782", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001782.tgz", - "integrity": "sha512-dZcaJLJeDMh4rELYFw1tvSn1bhZWYFOt468FcbHHxx/Z/dFidd1I6ciyFdi3iwfQCyOjqo9upF6lGQYtMiJWxw==", + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", "dev": true, "funding": [ { @@ -1676,9 +1739,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.329", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.329.tgz", - "integrity": "sha512-/4t+AS1l4S3ZC0Ja7PHFIWeBIxGA3QGqV8/yKsP36v7NcyUCl+bIcmw6s5zVuMIECWwBrAK/6QLzTmbJChBboQ==", + "version": "1.5.395", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", + "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", "dev": true, "license": "ISC" }, @@ -1723,9 +1786,9 @@ } }, "node_modules/eslint": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", - "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", "dependencies": { @@ -1734,8 +1797,8 @@ "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.5", - "@eslint/js": "9.39.4", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -1783,9 +1846,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", - "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", "dev": true, "license": "MIT", "dependencies": { @@ -1799,13 +1862,13 @@ "node": ">=18" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" } }, "node_modules/eslint-plugin-react-refresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.2.tgz", - "integrity": "sha512-hmgTH57GfzoTFjVN0yBwTggnsVUF2tcqi7RJZHqi9lIezSs4eFyAMktA68YD4r5kNw1mxyY4dmkyoFDb3FIqrA==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.3.tgz", + "integrity": "sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1996,9 +2059,9 @@ } }, "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", + "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", "dev": true, "license": "ISC" }, @@ -2050,9 +2113,9 @@ } }, "node_modules/globals": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz", - "integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", + "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", "dev": true, "license": "MIT", "engines": { @@ -2210,10 +2273,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -2299,9 +2372,9 @@ } }, "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, "license": "MPL-2.0", "dependencies": { @@ -2315,23 +2388,23 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", "cpu": [ "arm64" ], @@ -2350,9 +2423,9 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", "cpu": [ "arm64" ], @@ -2371,9 +2444,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", "cpu": [ "x64" ], @@ -2392,9 +2465,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", "cpu": [ "x64" ], @@ -2413,9 +2486,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", "cpu": [ "arm" ], @@ -2434,9 +2507,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", "cpu": [ "arm64" ], @@ -2455,9 +2528,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", "cpu": [ "arm64" ], @@ -2476,9 +2549,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", "cpu": [ "x64" ], @@ -2497,9 +2570,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", "cpu": [ "x64" ], @@ -2518,9 +2591,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", "cpu": [ "arm64" ], @@ -2539,9 +2612,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ "x64" ], @@ -2630,9 +2703,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "dev": true, "funding": [ { @@ -2656,11 +2729,14 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/object-assign": { "version": "4.1.1", @@ -2793,9 +2869,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", "engines": { @@ -2806,9 +2882,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", + "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", "dev": true, "funding": [ { @@ -2826,7 +2902,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2861,6 +2937,10 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/public-widget-sdk": { + "resolved": "../..", + "link": true + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -2872,30 +2952,30 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.8" } }, "node_modules/react-is": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.7.tgz", - "integrity": "sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", + "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", "license": "MIT" }, "node_modules/react-transition-group": { @@ -2945,14 +3025,15 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", - "integrity": "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", + "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@oxc-project/types": "=0.122.0", - "@rolldown/pluginutils": "1.0.0-rc.12" + "@oxc-project/types": "=0.140.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -2961,29 +3042,22 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", - "@rolldown/binding-darwin-x64": "1.0.0-rc.12", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" - } - }, - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.12.tgz", - "integrity": "sha512-HHMwmarRKvoFsJorqYlFeFRzXZqCt2ETQlEDOb9aqssrnVBB1/+xgTGtuTrIk5vzLNX1MjMtTf7W9z3tsSbrxw==", - "dev": true, - "license": "MIT" + "@rolldown/binding-android-arm64": "1.2.0", + "@rolldown/binding-darwin-arm64": "1.2.0", + "@rolldown/binding-darwin-x64": "1.2.0", + "@rolldown/binding-freebsd-x64": "1.2.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", + "@rolldown/binding-linux-arm64-gnu": "1.2.0", + "@rolldown/binding-linux-arm64-musl": "1.2.0", + "@rolldown/binding-linux-ppc64-gnu": "1.2.0", + "@rolldown/binding-linux-s390x-gnu": "1.2.0", + "@rolldown/binding-linux-x64-gnu": "1.2.0", + "@rolldown/binding-linux-x64-musl": "1.2.0", + "@rolldown/binding-openharmony-arm64": "1.2.0", + "@rolldown/binding-wasm32-wasi": "1.2.0", + "@rolldown/binding-win32-arm64-msvc": "1.2.0", + "@rolldown/binding-win32-x64-msvc": "1.2.0" + } }, "node_modules/scheduler": { "version": "0.27.0", @@ -3088,14 +3162,14 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -3167,17 +3241,17 @@ } }, "node_modules/vite": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.3.tgz", - "integrity": "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ==", + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", - "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.12", - "tinyglobby": "^0.2.15" + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -3193,8 +3267,8 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.1.0", - "esbuild": "^0.27.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", @@ -3244,6 +3318,330 @@ } } }, + "node_modules/vite/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3309,9 +3707,9 @@ } }, "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "dev": true, "license": "MIT", "funding": { diff --git a/test/my-app/package.json b/test/my-app/package.json index a6a8f091..bc311916 100644 --- a/test/my-app/package.json +++ b/test/my-app/package.json @@ -14,7 +14,8 @@ "@emotion/styled": "^11.14.1", "@mui/material": "^9.2.0", "react": "^19.2.4", - "react-dom": "^19.2.4" + "react-dom": "^19.2.4", + "public-widget-sdk": "file:../../" }, "devDependencies": { "@babel/core": "^7.29.0", diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 9a416f5f..be57fb70 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -4,12 +4,19 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "../../../src"; -import "../../../dist/style.css"; +import { CardWidget } from "public-widget-sdk"; + +// Import your stylesheet via the industry-standard subpath +import "public-widget-sdk/styles.css"; + +// import { CardWidget } from "../../../src"; +// import "../../../dist/style.css"; + + +const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; +const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; +const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; -const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; -const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); @@ -22,7 +29,7 @@ const node = anedya.newNode(client, nodeId); * built-in default β€” anything omitted falls back to lightTheme/darkTheme. */ const emeraldTheme= { - classNames: { + styles: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", value: "text-emerald-900", @@ -34,27 +41,27 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
+
{/* ============================================================ - * 1. Default appearance β€” no theme, no classNames, no + * 1. Default appearance β€” no theme, no styles, no * formatting props. Every fallback in the widget in one place. * ============================================================ */} - + {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same * effect across every widget instance that uses it. * ============================================================ */} - + {/* Built-in preset names also work directly: */} - + {/* ============================================================ - * 3. classNames vs className β€” THE distinction to understand: + * 3. styles vs className β€” THE distinction to understand: * - * - `classNames` (plural, an OBJECT): per-SLOT overrides. + * - `styles` (plural, an OBJECT): per-SLOT overrides. * Keys are "container" | "title" | "value" | "unit" | "label" * β€” lets you reach INSIDE the widget and style individual * pieces independently. @@ -63,20 +70,20 @@ export default function App() { * convention β€” one class applied ONLY to the widget's * outermost container element, same as you'd pass to any * other component. It's merged (via twMerge) with whatever - * classNames.container already resolved to, not a + * styles.container already resolved to, not a * replacement for it. * * This example uses BOTH at once so the difference is visible: - * className adds a shadow to the outer box, classNames.value/ - * classNames.title style two INNER pieces independently. + * className adds a shadow to the outer box, styles.value/ + * styles.title style two INNER pieces independently. * ============================================================ */} {/* ============================================================ - * 4. Plain CSS classes β€” classNames works with ANY class source, + * 4. Plain CSS classes β€” styles works with ANY class source, * not just Tailwind. These reference plain hand-written CSS * classes (e.g. defined in a .css file this app already imports). * ============================================================ */} - + decimalPlaces={1} + styles={{ container: "my-card", value: "my-card-value" }} + /> */} {/* ============================================================ * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` * work exactly as they do anywhere else in your app, because - * classNames just forwards whatever string you write straight + * styles just forwards whatever string you write straight * to `className`. This widget does NOT have its own custom * breakpoint system β€” these prefixes are compiled by YOUR * project's Tailwind config and respond to the BROWSER VIEWPORT, @@ -108,36 +115,37 @@ export default function App() { * automatically follow that customization too β€” nothing to * configure on the widget's side. * ============================================================ */} - + decimalPlaces={1} + styles={{ value: "text-2xl sm:text-3xl md:text-4xl lg:text-5xl" }} + /> */} {/* ============================================================ * 6. formatValue / labelText β€” simple formatting hooks, distinct * from styling. formatValue controls the displayed number's * text; labelText controls the caption under it. * ============================================================ */} - `${v.toFixed(2)} % RH`} labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - /> + + /> */} {/* ============================================================ * 7. onStyleChange β€” conditional class overrides driven by the * RAW fetched data ({ value, timestamp }), always applied on top - * of everything else (theme, classNames, className). + * of everything else (theme, styles, className). * ============================================================ */} - { if (!data) return; @@ -146,7 +154,7 @@ export default function App() { return { title: "High Humidity", theme: "dark", - classNames: { + styles: { value: "text-red-500" } }; @@ -158,14 +166,14 @@ export default function App() { }; }} - /> + /> */} {/* ============================================================ * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, * applied as inline styles on the container, independent of the - * whole classNames/theme system. + * whole styles/theme system. * ============================================================ */} - + {/* */}
); } \ No newline at end of file diff --git a/test/my-app/vite.config.js b/test/my-app/vite.config.js index 6ad23181..1543c923 100644 --- a/test/my-app/vite.config.js +++ b/test/my-app/vite.config.js @@ -11,6 +11,12 @@ export default defineConfig({ resolve: { dedupe: ["react", "react-dom", "@base-ui/react"], }, + server: { + fs: { + // Allow Vite to fetch assets from the parent widget SDK directory + allow: ['..'] + } + } }) diff --git a/ts.config.json b/ts.config.json index a2224bc5..ab5595da 100644 --- a/ts.config.json +++ b/ts.config.json @@ -10,7 +10,9 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "declaration": true, - "noEmit": true + "noEmit": true, + "types":["react", "react-dom"], + "isolatedDeclarations": true }, "include": ["src"] } \ No newline at end of file diff --git a/tsdown.config.ts b/tsdown.config.ts new file mode 100644 index 00000000..ea6b6752 --- /dev/null +++ b/tsdown.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "tsdown"; + +export default defineConfig({ + entry: ["src/index.ts"], + format: ["esm", "cjs"], + dts: true, + tsconfig: "./ts.config.json", + // Updated from external to deps.neverBundle + deps: { + neverBundle: ["react", "react-dom", "@base-ui/react"] + }, + clean: false, +}); diff --git a/tsup.config.ts b/tsup.config.ts deleted file mode 100644 index 42f9e6ce..00000000 --- a/tsup.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from "tsup"; - -export default defineConfig({ - entry: ["src/index.ts"], - format: ["esm", "cjs"], - dts: true, - tsconfig: "./ts.config.json", - external: ["react", "react-dom", "@base-ui/react"], - clean: false, -}); \ No newline at end of file From 0d281af21b87729a251ea8e4b71f07ffbe556987 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 08:51:49 +0530 Subject: [PATCH 26/66] read me updated --- README.md | 127 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 73 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 6a0cc425..3d5c878f 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,59 @@ -# CardWidget +[PyPI](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk)  [Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js) -A single-value display widget for Anedya data β€” shows the latest reading, a title, and a last-updated label. + + +

+ Logo +

+ + +# Anedya Widgets SDK + +A collection of pre-built, themeable React widgets for displaying Anedya IoT data β€” drop-in components for dashboards and front-end apps. ## Table of Contents -- [Setup](#setup) -- [Required props](#required-props) -- [The styling model](#the-styling-model) -- [`styles` vs `className`](#styles-vs-classname--the-distinction-that-matters-most) -- [Theming](#theming) -- [Tailwind responsive utilities](#tailwind-responsive-utilities) -- [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) -- [How props are resolved](#how-props-are-resolved) -- [Formatting vs rendering](#formatting-vs-rendering) -- [Sizing](#sizing) -- [Responsive sizing](#responsive-sizing) -- [Loading & error states](#loading--error-states) -- [Other props](#other-props) +- [Installation & Setup](#installation--setup) +- [Widgets](#widgets) + - [CardWidget](#cardwidget) + - [Required props](#required-props) + - [The styling model](#the-styling-model) + - [`styles` vs `className`](#styles-vs-classname--the-distinction-that-matters-most) + - [Theming](#theming) + - [Tailwind responsive utilities](#tailwind-responsive-utilities) + - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) + - [How props are resolved](#how-props-are-resolved) + - [Formatting vs rendering](#formatting-vs-rendering) + - [Sizing](#sizing) + - [Responsive sizing](#responsive-sizing) + - [Loading & error states](#loading--error-states) + - [Other props](#other-props) - [Build & distribution](#build--distribution--why-classes-render-unstyled-without-this) --- -## Setup -`CardWidget` doesn't create its own SDK client or node β€” it only renders data you fetch through the [Anedya Frontend SDK](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk), which is a separate package you'll need alongside this one. +## Installation & Setup + +Widgets in this SDK don't create their own Anedya client or node β€” they only render data you fetch through the [Anedya Frontend SDK](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk), which is a separate package you'll need alongside this one. **1. Install both packages:** ```bash -npm install @anedyasystems/anedya-frontend-sdk your-sdk +npm install @anedyasystems/anedya-frontend-sdk public-widget-sdk ``` -**2. Create a client and node using the Frontend SDK, then pass the node into `CardWidget`:** +**2. Import the stylesheet once**, anywhere in your app's entry point: + +```jsx +import "public-widget-sdk/styles.css"; +``` + +**3. Create a client and node using the Frontend SDK, then pass the node into any widget:** ```jsx import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "your-sdk"; +import { CardWidget } from "public-widget-sdk"; +import "public-widget-sdk/styles.css"; const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); @@ -44,11 +63,21 @@ const node = anedya.newNode(client, nodeId); ``` -> `tokenId`, `token`, and `nodeId` come from your Anedya account/device setup β€” see the [Frontend SDK docs](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk) for details on obtaining these and on other `node`/`client` methods (fetching historical data, live streaming, key-value store, etc.) beyond what this widget itself uses. +> `tokenId`, `token`, and `nodeId` come from your Anedya account/device setup β€” see the [Frontend SDK docs](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk) for details on obtaining these and on other `node`/`client` methods (fetching historical data, live streaming, key-value store, etc.) beyond what these widgets use directly. --- -## Required props +## Widgets + +### CardWidget + +A single-value display widget β€” shows the latest reading, a title, and a last-updated label. + +```jsx + +``` + +#### Required props | Prop | Type | Description | |---|---|---| @@ -57,7 +86,7 @@ const node = anedya.newNode(client, nodeId); --- -## The styling model +#### The styling model `CardWidget` is **entirely class-based** β€” every visual choice is a CSS class string, not a style property. This is deliberate: card widgets are commonly styled with Tailwind, and classes compose and override far more predictably than inline styles do once you're combining a theme, a per-instance override, and a conditional rule all on the same element. @@ -69,7 +98,7 @@ type CardSlot = "container" | "title" | "value" | "unit" | "label"; --- -## `styles` vs `className` β€” the distinction that matters most +#### `styles` vs `className` β€” the distinction that matters most These look similar but do genuinely different things: @@ -90,16 +119,16 @@ These look similar but do genuinely different things: Both can be used together freely β€” `className` is merged (via `twMerge`) with whatever `styles.container` already resolved to; it doesn't replace it. -> **Note:** `styles` classes are consumer-authored strings forwarded straight into `className` at render β€” the widget doesn't generate any CSS for them at build time. Any class you pass here must already exist in your own app's compiled CSS (e.g. your own Tailwind build, or a plain hand-written class in a stylesheet you import) β€” arbitrary utility names that only the widget's *own* Tailwind build knows about (like the container-query variables described below) won't do anything if typed fresh from a consuming app. +> **Note:** `styles` classes are consumer-authored strings forwarded straight into `className` at render β€” the widget doesn't generate any CSS for them at build time. Any class you pass here must already exist in your own app's compiled CSS (e.g. your own Tailwind build, or a plain hand-written class in a stylesheet you import). --- -## Theming +#### Theming `theme` accepts a built-in preset name, or a full custom `WidgetTheme` object β€” just a plain object shaped like `styles`, reusable across every widget instance that uses it: ```jsx -const emeraldTheme: WidgetTheme = { +const emeraldTheme = { styles: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", @@ -115,7 +144,7 @@ const emeraldTheme: WidgetTheme = { --- -## Tailwind responsive utilities +#### Tailwind responsive utilities You can freely use Tailwind's responsive prefixes inside `styles`: @@ -133,7 +162,7 @@ If you supply your own `text-*` classes (responsive or otherwise), they replace --- -## `onDataChange` β€” data-driven rendering +#### `onDataChange` β€” data-driven rendering `onDataChange` is called whenever the latest fetched data changes. @@ -171,7 +200,7 @@ Returning `undefined` (or nothing) clears any previous overrides and restores th --- -## How props are resolved +#### How props are resolved Rendering happens in layers. @@ -194,7 +223,7 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve --- -## Formatting vs rendering +#### Formatting vs rendering `formatValue` and `labelText` control **what text is displayed**. @@ -202,8 +231,6 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve `onDataChange` can override either one (along with most other widget props), allowing the widget to react to incoming data. -For example: - ```tsx `${v.toFixed(2)} % RH`} @@ -227,7 +254,7 @@ For example: --- -## Sizing +#### Sizing `width` / `height` / `minWidth` / `maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole `styles`/theme system: @@ -235,7 +262,7 @@ For example: ``` -### `height` has two distinct modes +##### `height` has two distinct modes Whether you pass `height` changes how the card behaves β€” this is intentional, not a quirk: @@ -256,7 +283,7 @@ If you're using a `formatValue` that can produce long strings, either don't pass --- -## Responsive sizing +#### Responsive sizing The widget automatically scales its internal spacing and typography using **CSS Container Queries** β€” based on the card's own rendered size, not the browser viewport. @@ -275,12 +302,10 @@ By default the following properties scale automatically: A card inside a narrow dashboard column will use smaller typography than the same card rendered full-width, even on the same screen β€” this behavior is built in and needs no configuration. -### Overriding responsive sizing +##### Overriding responsive sizing If you provide your own font-size utility for a slot, you're opting out of the default responsive sizing for that slot. -For example: - ```tsx ``` -The value will always render at `text-6xl`. +The value will always render at `text-6xl`. Likewise, responsive Tailwind classes (`text-2xl md:text-5xl`) take precedence over the widget's default responsive sizing β€” your classes always win over the widget defaults. -Likewise, if you provide responsive Tailwind classes: - -```tsx -styles={{ - value: "text-2xl md:text-5xl" -}} -``` +--- -your own breakpoint rules take precedence over the widget's default responsive sizing. This follows normal Tailwind behavior β€” your classes always win over the widget defaults. +#### Loading & error states ---- +While the initial fetch is in flight, the card renders **skeleton loaders** in place of the value and label β€” pulsing placeholder blocks sized to match each slot's current font-size variable (`var(--anedya-card-value-size)` / `var(--anedya-card-label-size)`), so the skeleton scales along with the card exactly like the real content would. -## Loading & error states +If the fetch fails or no data is available, the card renders the error message text in place of the value (title still renders normally). -While the initial fetch is in flight, the card renders a small spinner in place of the value. If the fetch fails or no data is available, the card renders the error message text in place of the value (title and label still render normally). Neither state currently accepts style overrides via `styles` β€” flag it if you need to customize their appearance. +Neither state currently accepts style overrides via `styles` β€” flag it if you need to customize their appearance. --- -## Other props +#### Other props | Prop | Type | Description | |---|---|---| @@ -356,10 +375,10 @@ npm install -D @tailwindcss/cli Run it as part of your normal publish/build step so `dist/style.css` always reflects the current source. -**4. Consumers import it once**, anywhere in their app: +**4. Consumers import it once**, via the package's `styles.css` subpath export: ```jsx -import "your-sdk/dist/style.css"; +import "public-widget-sdk/styles.css"; ``` That's the entire integration on their end β€” no `content` glob changes, no Tailwind config coordination, no knowledge of how this SDK is built internally required. From 7d50f1c36a4d83a65444c82d24daf590afa2495f Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 08:55:19 +0530 Subject: [PATCH 27/66] added contributing md --- CONTRIBUTING.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 47 ++++++----------------------------------- 2 files changed, 62 insertions(+), 41 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..28d2a46a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,56 @@ +# Contributing + +This document covers internal build setup for people working on this SDK itself β€” not consumers installing the package. If you're looking for how to *use* the widgets, see [README.md](./README.md). + +## Table of Contents + +- [Why this exists](#why-this-exists) +- [Setting up the stylesheet build](#setting-up-the-stylesheet-build) +- [Adding a new widget's classes to the build](#adding-a-new-widgets-classes-to-the-build) + +--- + +## Why this exists + +Since this SDK is installed as a real package (not copied into the consumer's own repo, the way shadcn/ui works), the consumer's own Tailwind build **never scans this package's source files** by default β€” so every class string in files like `themes/defaultTheme.ts` / `CARD_DEFAULT_CLASSES` compiles to nothing in their app, and every widget would render with zero layout or color. + +The fix: this SDK ships its **own pre-compiled stylesheet** as part of its build, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. This is why every consumer-facing widget needs `import "public-widget-sdk/styles.css"` β€” see the README's [Stylesheet import](./README.md#stylesheet-import) section for the consumer-facing side of this. + +--- + +## Setting up the stylesheet build + +**1. The input file**, `src/styles/base.css`: + +```css +@import "tailwindcss"; + +/* Explicit @source directives so Tailwind scans exactly the folders + containing our class strings, rather than relying purely on + automatic detection. Paths are relative to this file's location. */ +@source "../widgets/**/*.{ts,tsx}"; +@source "../themes/**/*.{ts,tsx}"; +@source "../common.ts"; +``` + +**2. Install the Tailwind v4 CLI** (a separate package from core `tailwindcss` as of v4): + +```bash +npm install -D @tailwindcss/cli +``` + +**3. Build script**, in `package.json`: + +```json +{ + "scripts": { + "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify", + "build:js": "tsup", + "build": "npm run build:js && npm run build:css" + } +} +``` + +> **Order matters:** `build:js` must run before `build:css` if `tsup`'s `clean` option is enabled β€” `tsup` wipes `dist/` before writing its own output, which would delete `style.css` if the CSS step ran first. + +Run \ No newline at end of file diff --git a/README.md b/README.md index 3d5c878f..19b136b8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [Responsive sizing](#responsive-sizing) - [Loading & error states](#loading--error-states) - [Other props](#other-props) -- [Build & distribution](#build--distribution--why-classes-render-unstyled-without-this) +- [Stylesheet import](#stylesheet-import) --- @@ -338,51 +338,16 @@ Neither state currently accepts style overrides via `styles` β€” flag it if you --- -## Build & distribution β€” why classes render unstyled without this +## Stylesheet import -Since this SDK is installed as a real package (not copied into the consumer's own repo, the way shadcn/ui works), the consumer's own Tailwind build **never scans this package's source files** by default β€” so every class string in `themes/defaultTheme.ts`/`CARD_DEFAULT_CLASSES` compiles to nothing in their app, and every widget renders with zero layout or color. This isn't a bug in the widget; it's a structural consequence of shipping Tailwind classes from an installable package. +This SDK ships pre-compiled CSS alongside its JavaScript β€” you don't need Tailwind configured in your own project for these widgets to render correctly, even if you don't use Tailwind at all. -**The fix: ship a pre-compiled stylesheet as part of this SDK's own build**, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. - -**1. Create the input file**, `src/styles/base.css`: - -```css -@import "tailwindcss"; - -/* Explicit @source directives so Tailwind scans exactly the folders - containing our class strings, rather than relying purely on - automatic detection. Paths are relative to this file's location. */ -@source "../widgets/**/*.{ts,tsx}"; -@source "../themes/**/*.{ts,tsx}"; -@source "../common.ts"; -``` - -**2. Install the Tailwind v4 CLI** (a separate package from core `tailwindcss` as of v4): - -```bash -npm install -D @tailwindcss/cli -``` - -**3. Add a build script**, in `package.json`: - -```json -{ - "scripts": { - "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/style.css --minify" - } -} -``` - -Run it as part of your normal publish/build step so `dist/style.css` always reflects the current source. - -**4. Consumers import it once**, via the package's `styles.css` subpath export: +**Import the stylesheet once**, anywhere in your app's entry point (e.g. `main.tsx`, `App.tsx`, or your global styles file): ```jsx import "public-widget-sdk/styles.css"; ``` -That's the entire integration on their end β€” no `content` glob changes, no Tailwind config coordination, no knowledge of how this SDK is built internally required. - ---- +That's the entire integration on your end. No `content` glob changes to your `tailwind.config`, no build coordination, nothing else required β€” every widget in this SDK will render fully styled as soon as this import is present. -- `style` (a plain inline-style object, part of the shared base props every widget accepts) isn't currently wired into the container's render β€” only `className` is. If you need it, flag it and it can be added the same way `className` already works. \ No newline at end of file +> **If styles aren't appearing:** double-check the import path matches your installed package name exactly, and that it's imported somewhere that actually runs before your widgets render (e.g. not inside a conditionally-loaded file). If you're using a bundler with strict CSS module resolution, confirm it supports subpath imports from `node_modules` (most modern bundlers β€” Vite, Webpack 5+, Next.js β€” do, out of the box). \ No newline at end of file From 76a345baf0a80ad3dee57e6804a672ffb57625d3 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 09:09:09 +0530 Subject: [PATCH 28/66] removed unused imports and added contributing file --- CONTRIBUTING.md | 101 +++++++++++++++++++++++++++++++++++++++- test/my-app/src/App.jsx | 3 +- 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28d2a46a..e0d77609 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,7 @@ This document covers internal build setup for people working on this SDK itself - [Why this exists](#why-this-exists) - [Setting up the stylesheet build](#setting-up-the-stylesheet-build) - [Adding a new widget's classes to the build](#adding-a-new-widgets-classes-to-the-build) +- [Local development](#local-development) --- @@ -53,4 +54,102 @@ npm install -D @tailwindcss/cli > **Order matters:** `build:js` must run before `build:css` if `tsup`'s `clean` option is enabled β€” `tsup` wipes `dist/` before writing its own output, which would delete `style.css` if the CSS step ran first. -Run \ No newline at end of file +Run `npm run build` before every publish so `dist/style.css` always reflects current source. Consider chaining this into `prepublishOnly` so it can't be forgotten: + +```json +{ + "scripts": { + "prepublishOnly": "npm run build" + } +} +``` + +--- + +## Adding a new widget's classes to the build + +Whenever you add a new widget (e.g. `ChartWidget`), make sure its default classes and theme files live somewhere already covered by the `@source` globs in `base.css` β€” or add a new `@source` line pointing at wherever they live: + +```css +@source "../widgets/**/*.{ts,tsx}"; /* covers src/widgets/**, including new widget folders */ +@source "../themes/**/*.{ts,tsx}"; /* covers src/themes/**, including new theme files */ +``` + +If a new widget's classes live outside these paths, they silently won't compile β€” same failure mode described in [Why this exists](#why-this-exists), just for a *new* widget's classes instead of the whole package. After adding any new source file, rebuild and grep for a known class to confirm it made it into `dist/style.css`: + +```bash +npm run build:css +grep "your-new-class-name" dist/style.css +``` + +--- + +## Local development + +The demo app (`my-app`) is used to manually test widgets while working on this SDK. Set it up using `npm link`, which symlinks your local package into the demo β€” no `file:` reference in `package.json` needed. + +### One-time setup + +**1. In the package root**, register it as linkable: + +```bash +npm link +``` + +**2. In the demo app**, link to it: + +```bash +npm link public-widget-sdk +``` + +This creates a symlink from the demo's `node_modules/public-widget-sdk` to your local package root β€” the demo now resolves that import to your local working copy instead of anything published to npm. + +### Two ways to import while developing + +**Option A β€” import directly from source (fastest iteration)** + +```jsx +import { CardWidget } from "../../../src"; +import "../../../dist/style.css"; +``` + +Use this while actively developing a widget's component code (`.tsx` logic, props, structure). JS changes are picked up by the demo's own dev server via normal React/Vite hot-reload β€” no rebuild of the SDK package itself required. + +**Caveat:** the imported stylesheet (`../../../dist/style.css`) is still a *built* artifact, not the raw `base.css` β€” so any CSS/Tailwind class change still needs: + +```bash +npm run build:css +``` +before it shows up in the demo, even in this mode. + +**Option B β€” import as the published package (accurate consumer simulation)** + +```jsx +import { CardWidget } from "public-widget-sdk"; +import "public-widget-sdk/styles.css"; +``` + +Use this to verify the package behaves correctly as an actual installed dependency β€” e.g. confirming `exports` map entries resolve correctly, the stylesheet subpath import works, and nothing that only exists in the local `src/` folder (but wasn't actually exported) is accidentally being relied on. + +Because the link points at your package root, any rebuild there is picked up automatically: + +```bash +npm run build +``` + +No re-linking needed after this, **unless** you change the package's `name` field or its `exports` map β€” in either case, re-run `npm link` in both the package root and the demo to refresh the symlink. + +### Switching between the two + +The demo file typically keeps both import blocks present, with one commented out β€” swap which is active depending on which mode you're testing in. + +Two things worth knowing if changes don't seem to show up: + +- **Vite's dependency pre-bundling cache** may have optimized an older version of the package. If Option B isn't reflecting a fresh build, clear it and restart: +```bash + rm -rf node_modules/.vite + npm run dev +``` +- Restart the demo's dev server (not just save/hot-reload) after switching which import block is active β€” changing which module resolves `CardWidget` can require a fresh module graph. + +**Rule of thumb:** use Option A day-to-day while iterating on a widget; switch to Option B before committing/publishing, as a final sanity check that the consumer-facing package actually works the way the README describes. \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index be57fb70..4082c4d0 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -9,8 +9,7 @@ import { CardWidget } from "public-widget-sdk"; // Import your stylesheet via the industry-standard subpath import "public-widget-sdk/styles.css"; -// import { CardWidget } from "../../../src"; -// import "../../../dist/style.css"; + const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; From 478ab1dbd039177c2252adb93a21f5c281eb12d5 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 09:11:42 +0530 Subject: [PATCH 29/66] Stop tracking dist/ (already in .gitignore) --- dist/index.d.mts | 129 ---------------------------------- dist/index.mjs | 177 ----------------------------------------------- 2 files changed, 306 deletions(-) delete mode 100644 dist/index.d.mts delete mode 100644 dist/index.mjs diff --git a/dist/index.d.mts b/dist/index.d.mts deleted file mode 100644 index 48c03f35..00000000 --- a/dist/index.d.mts +++ /dev/null @@ -1,129 +0,0 @@ -//#region src/types/card.d.ts -type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; -type BuiltInTheme = "light" | "dark"; -//#endregion -//#region src/types/root.d.ts -/** - * Generic per-slot class overrides. Every widget defines its own slot - * names (Card: container/title/value/unit/label, Chart: container/line/ - * axis/...) but they all share this same shape. - */ -type SlotClassNames = Partial>; -/** - * A widget theme is simply a reusable collection of Tailwind (or plain - * CSS) classes for a widget's slots. - * - * Themes are merged in three layers: - * - * built-in theme - * ↓ - * user theme - * ↓ - * widget styles prop - * - * Later layers win via `twMerge`. - */ -interface WidgetTheme { - styles: SlotClassNames; -} -//#endregion -//#region src/common.d.ts -/** - * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`decimalPlaces`, Chart's `tickCount`) extend this - * rather than repeating client/node/sizing/theme plumbing per widget. - * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. - */ -interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `styles` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - /** - * Card height in pixels. - * - If provided: treated as a fixed size. Content that doesn't fit will be clipped. - * - If omitted: the card grows to fit its content naturally. - */ - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; -} -//#endregion -//#region src/components/CardWidget.d.ts -type CardSlot = "container" | "title" | "value" | "unit" | "label"; -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -interface CardData { - value: number; - timestamp: number; -} -type CardWidgetUpdate = Partial>; -interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - decimalPlaces?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - styles?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * styles: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; -} -declare function CardWidget({ node, variable, title, unit, decimalPlaces, formatValue, labelText, styles, onDataChange, theme, className, width, height, minWidth, maxWidth }: CardWidgetProps): React.JSX.Element; -//#endregion -export { CardWidget }; \ No newline at end of file diff --git a/dist/index.mjs b/dist/index.mjs deleted file mode 100644 index d51d9874..00000000 --- a/dist/index.mjs +++ /dev/null @@ -1,177 +0,0 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import { twMerge } from "tailwind-merge"; -import { Fragment, jsx, jsxs } from "react/jsx-runtime"; -//#region src/themes/defaultTheme.ts -const CARD_DEFAULT_CLASSES = { - title: "text-[length:var(--anedya-card-title-size)] font-medium", - value: "text-[length:var(--anedya-card-value-size)] font-bold max-w-full min-w-0 leading-tight", - unit: "text-[length:var(--anedya-card-unit-size)]", - label: "text-[length:var(--anedya-card-label-size)]", - container: "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" -}; -const lightTheme = { styles: { - container: "bg-white border-slate-200", - title: "text-slate-500", - value: "text-slate-900", - label: "text-slate-400" -} }; -const darkTheme = { styles: { - container: "bg-slate-900 border-slate-800", - title: "text-slate-400", - value: "text-white", - label: "text-slate-500" -} }; -//#endregion -//#region src/components/CardWidget.tsx -const DEFAULT_WIDTH = 240; -const DEFAULT_HEIGHT = 160; -const DEFAULT_MIN_WIDTH = 180; -const DEFAULT_MAX_WIDTH = 480; -function CardWidget({ node, variable, title = "Latest Value", unit, decimalPlaces, formatValue, labelText, styles = {}, onDataChange, theme, className, width, height, minWidth = DEFAULT_MIN_WIDTH, maxWidth = DEFAULT_MAX_WIDTH }) { - const [value, setValue] = useState(null); - const [timestamp, setTimestamp] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [dynamicProps, setDynamicProps] = useState({}); - const mountedRef = useRef(false); - const isFetchingRef = useRef(false); - useEffect(() => { - if (!node) return; - mountedRef.current = true; - const fetchLatest = async () => { - if (isFetchingRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - try { - const res = await node.getLatestData(variable); - if (!mountedRef.current) return; - if (res.isSuccess && res.isDataAvailable) { - setValue(res.data.value); - setTimestamp(res.data.timestamp); - } else { - setValue(null); - setError(res.error?.errorMessage ?? "No data available"); - } - } catch (err) { - if (!mountedRef.current) return; - setValue(null); - setError(err?.message ?? "Failed to fetch data"); - } finally { - if (mountedRef.current) { - setLoading(false); - isFetchingRef.current = false; - } - } - }; - fetchLatest(); - return () => { - mountedRef.current = false; - }; - }, [node, variable]); - useEffect(() => { - if (!onDataChange) { - setDynamicProps({}); - return; - } - setDynamicProps(onDataChange(value != null && timestamp != null ? { - value, - timestamp - } : null) ?? {}); - }, [ - value, - timestamp, - onDataChange - ]); - const resolvedProps = { - title, - unit, - decimalPlaces, - formatValue, - labelText, - width: width ?? DEFAULT_WIDTH, - height, - minWidth, - maxWidth, - className, - theme, - ...dynamicProps, - styles: { - ...styles ?? {}, - ...dynamicProps.styles ?? {} - } - }; - const resolvedTheme = resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" ? lightTheme : resolvedProps.theme ?? lightTheme; - const resolveSlot = (slot) => twMerge(CARD_DEFAULT_CLASSES[slot], resolvedTheme.styles[slot], resolvedProps.styles[slot]); - const displayValue = useMemo(() => { - if (value == null) return null; - if (resolvedProps.formatValue) return resolvedProps.formatValue(value); - if (resolvedProps.decimalPlaces != null) return value.toFixed(resolvedProps.decimalPlaces); - return String(value); - }, [ - value, - resolvedProps.formatValue, - resolvedProps.decimalPlaces - ]); - const displayLabel = useMemo(() => { - if (timestamp == null) return null; - if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); - return `Updated ${(timestamp < 0xe8d4a51000 ? /* @__PURE__ */ new Date(timestamp * 1e3) : new Date(timestamp)).toLocaleTimeString()}`; - }, [timestamp, resolvedProps.labelText]); - const hasExplicitHeight = height != null || dynamicProps.height != null; - return /* @__PURE__ */ jsx("div", { - className: "anedya-card-container", - style: { - width: resolvedProps.width, - minWidth: resolvedProps.minWidth, - maxWidth: resolvedProps.maxWidth, - ...hasExplicitHeight ? { height: resolvedProps.height } : { minHeight: DEFAULT_HEIGHT }, - boxSizing: "border-box", - display: "flex", - flexDirection: "column" - }, - children: /* @__PURE__ */ jsxs("div", { - className: twMerge("anedya-card", resolveSlot("container"), resolvedProps.className), - style: { - flex: "1 0 auto", - ...hasExplicitHeight ? { overflow: "hidden" } : {} - }, - children: [/* @__PURE__ */ jsx("span", { - className: resolveSlot("title"), - children: resolvedProps.title - }), loading ? /* @__PURE__ */ jsxs("div", { - className: "flex flex-col gap-[var(--anedya-card-gap)] w-full items-center justify-center", - children: [/* @__PURE__ */ jsx("div", { - className: "w-2/3 bg-slate-200 dark:bg-slate-700 rounded-md animate-pulse", - style: { - height: "var(--anedya-card-value-size)", - backgroundColor: theme === "dark" ? "#374151" : "#e5e7eb" - } - }), /* @__PURE__ */ jsx("div", { - className: "w-1/2 bg-slate-200 dark:bg-slate-700 rounded-md animate-pulse", - style: { - height: "var(--anedya-card-label-size)", - backgroundColor: theme === "dark" ? "#374151" : "#e5e7eb" - } - })] - }) : error ? /* @__PURE__ */ jsx("span", { - className: "text-red-600 text-sm", - children: error - }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", { - className: twMerge("inline-flex items-baseline justify-center gap-1", resolveSlot("value")), - children: [/* @__PURE__ */ jsx("span", { - className: "min-w-0 break-words", - children: displayValue - }), resolvedProps.unit && /* @__PURE__ */ jsx("span", { - className: resolveSlot("unit"), - children: resolvedProps.unit - })] - }), displayLabel && /* @__PURE__ */ jsx("span", { - className: resolveSlot("label"), - children: displayLabel - })] })] - }) - }); -} -//#endregion -export { CardWidget }; From 805fd1c972ef53a3ee4478bc375a97412b598b10 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 09:54:12 +0530 Subject: [PATCH 30/66] added format, formatOptions,labelFormat,relativeTime export and updated read me --- README.md | 220 ++++++++++++++++++++++++------- package.json | 9 +- src/common.ts | 18 ++- src/components/CardWidget.tsx | 236 +++++++++++++++++++++------------- src/helpers/formatters.ts | 132 +++++++++++++++++++ test/my-app/src/App.jsx | 10 +- tsdown.config.ts | 5 +- 7 files changed, 492 insertions(+), 138 deletions(-) create mode 100644 src/helpers/formatters.ts diff --git a/README.md b/README.md index 19b136b8..41b133eb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ [PyPI](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk)  [Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js) -

Logo @@ -23,11 +22,13 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [Tailwind responsive utilities](#tailwind-responsive-utilities) - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) - [How props are resolved](#how-props-are-resolved) - - [Formatting vs rendering](#formatting-vs-rendering) - - [Sizing](#sizing) - - [Responsive sizing](#responsive-sizing) - - [Loading & error states](#loading--error-states) - - [Other props](#other-props) + - [Formatting vs rendering](#formatting-vs-rendering) +- [The last-updated label](#the-last-updated-label) +- [Formatters export](#formatters-export) + - [Sizing](#sizing) + - [Responsive sizing](#responsive-sizing) + - [Loading & error states](#loading--error-states) + - [Other props](#other-props) - [Stylesheet import](#stylesheet-import) --- @@ -60,7 +61,7 @@ const config = anedya.newConfig(tokenId, token); const client = anedya.newClient(config); const node = anedya.newNode(client, nodeId); - +; ``` > `tokenId`, `token`, and `nodeId` come from your Anedya account/device setup β€” see the [Frontend SDK docs](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk) for details on obtaining these and on other `node`/`client` methods (fetching historical data, live streaming, key-value store, etc.) beyond what these widgets use directly. @@ -74,15 +75,21 @@ const node = anedya.newNode(client, nodeId); A single-value display widget β€” shows the latest reading, a title, and a last-updated label. ```jsx - + ``` #### Required props -| Prop | Type | Description | -|---|---|---| -| `node` | `any` | `anedya.newNode(client, nodeId)` | -| `variable` | `string` | Variable name to display | +| Prop | Type | Description | +| ---------- | -------- | -------------------------------- | +| `node` | `any` | `anedya.newNode(client, nodeId)` | +| `variable` | `string` | Variable name to display | --- @@ -102,17 +109,17 @@ type CardSlot = "container" | "title" | "value" | "unit" | "label"; These look similar but do genuinely different things: -| | Shape | Targets | Purpose | -|---|---|---|---| -| `styles` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) *and* `container` | reach inside the widget | -| `className` | plain string | only the outermost container element | the ordinary React convention every component supports | +| | Shape | Targets | Purpose | +| ----------- | --------------------- | -------------------------------------------------------------------- | ------------------------------------------------------ | +| `styles` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) _and_ `container` | reach inside the widget | +| `className` | plain string | only the outermost container element | the ordinary React convention every component supports | ```jsx ``` @@ -151,7 +158,7 @@ You can freely use Tailwind's responsive prefixes inside `styles`: ```tsx ``` @@ -174,6 +181,7 @@ It receives the raw fetched data: timestamp: number; } ``` + (or `null` while no data is available). Instead of returning CSS classes, it returns a **partial set of widget props**. Those returned props temporarily override the widget's original props until the callback runs again. @@ -225,28 +233,91 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve #### Formatting vs rendering -`formatValue` and `labelText` control **what text is displayed**. +`format`, `formatOptions`, `decimalPlaces`, and `labelFormat` control **what text is displayed**. `styles` controls **how the widget looks**. -`onDataChange` can override either one (along with most other widget props), allowing the widget to react to incoming data. +`onDataChange` can override any of these (along with most other widget props), allowing the widget to react to incoming data. + +##### `format` β€” named presets for common unit types + +For values that need unit-aware scaling (bytes, durations, lengths, etc.), pass a `format` preset instead of manually computing a unit string: + +```tsx + +// renders "512" + "MB" β€” auto-scaled, no manual unit needed + + +// renders "2d 4h 12m" + + +// renders "1.25" + "km" +``` + +Available presets: + +| Preset | Input | Output example | +| ---------- | --------------- | ----------------------------------------------------------------------------------------------- | +| `number` | any | `"123,456"` β€” locale-aware thousands separators | +| `bytes` | bytes | `"500"` + `"KB"` β€” auto-scales B/KB/MB/GB/TB (or KiB/MiB/GiB with `formatOptions.binary: true`) | +| `duration` | seconds | `"2h 15m 30s"` | +| `length` | meters | `"1.25"` + `"km"` β€” auto-scales mm/cm/m/km | +| `volume` | milliliters | auto-scales mL/L | +| `dataRate` | bits per second | auto-scales bps/Kbps/Mbps | +| `percent` | 0–100 | `"45%"` | + +`formatOptions` accepts: + +```ts +{ + locale?: string; // BCP 47 tag, e.g. "en-IN" β€” defaults to browser locale + binary?: boolean; // bytes only: 1024-based (KiB/MiB) vs 1000-based (KB/MB) + precision?: number; // decimal places for the scaled number +} +``` + +**When to use each option:** + +- **`locale`** β€” force a specific number format instead of relying on the visitor's browser/OS locale. Useful for a dashboard serving a specific region, or an app with its own explicit language setting: +```tsx + + // "1,23,456" (Indian digit grouping) instead of "123,456" + + + // "123.456" (German uses "." as the thousands separator, "," as the decimal point) +``` + +- **`precision`** β€” control decimal places in the *scaled* output (not the raw value). Useful when the default rounding is too coarse for scientific/financial data, or you want whole numbers for a cleaner dashboard look: +```tsx + + // "512.34" + "MB" β€” more decimal places than the default + + + // "512" + "MB" β€” whole number, no decimals +``` + +- **`binary`** β€” *(`bytes` preset only)* choose between 1000-based and 1024-based scaling. These genuinely produce different numbers for the same raw byte count, so picking the wrong one can make a value look incorrect even though the math is technically right for the mode you're in: +```tsx + + // raw 1048576 -> "1" + "MiB" β€” matches how OS file managers/RAM usage are usually reported + + + // raw 1048576 -> "1.05" + "MB" β€” matches how storage manufacturers/network specs are usually reported +``` + As a rule of thumb: use `binary: true` for memory/RAM/file-size-on-disk readings, and the default (decimal) for network throughput or storage capacity marketing figures. + +**`format` takes over the `unit` slot entirely.** When set, the preset determines its own unit per value (e.g. switching from `"KB"` to `"MB"` as a byte count grows) β€” the `unit` prop is ignored while `format` is active. + +> **Presets don't validate that they match your data's actual meaning** β€” they only know how to scale a raw number. Applying `format="length"` to a Celsius reading, for example, will scale it as if it were meters and display a plausible-looking but semantically wrong unit. Only use a preset that matches what the underlying value actually represents. + +##### Precedence + +`formatValue` always wins if provided β€” it's a full custom formatting function and bypasses `format`/`decimalPlaces` entirely: ```tsx `${v.toFixed(2)} % RH`} labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - onDataChange={(data) => { - if (!data) return; - - if (data.value > 80) { - return { - title: "High Humidity", - styles: { - value: "text-red-500", - }, - }; - } - }} /> ``` @@ -254,6 +325,67 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve --- +#### The last-updated label + +By default, the label under the value shows a fixed clock time (`"Updated 14:32:10"`). This can be changed with `labelFormat`, or fully replaced with `labelText`. + +##### `labelFormat` β€” named presets + +```tsx + +// "5 minutes ago" instead of "Updated 14:32:10" + + +// "Updated 7/24/2026" +``` + +Available presets: + +| Preset | Output example | +| ---------------- | --------------------------------- | +| `time` (default) | `"Updated 14:32:10"` | +| `date` | `"Updated 7/24/2026"` | +| `datetime` | `"Updated 7/24/2026, 2:32:10 PM"` | +| `relative` | `"5 minutes ago"` | +| `iso` | `"2026-07-24T14:32:10.000Z"` | + +##### `labelText` β€” full custom control + +`labelText` always takes precedence over `labelFormat` and receives the raw timestamp, so you can use it for anything the presets don't cover β€” 12-hour/AM-PM formatting, hours-only, non-default locales, or combining relative time with custom surrounding text: + +```tsx +// AM/PM, 12-hour + { + const d = new Date(ts < 1e12 ? ts * 1000 : ts); + return `Updated ${d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", hour12: true })}`; + }} +/>; +// "Updated 2:32 PM" + +// Combining relative time with custom text +import { relativeTime } from "public-widget-sdk/formatters"; + + `Last synced ${relativeTime(ts)}`} />; +// "Last synced 5 minutes ago" +``` + +`labelFormat` covers the common cases with zero code; `labelText` is the general escape hatch for everything else β€” the same relationship `formatValue` has with `format`. + +--- + +#### Formatters export + +The formatting helpers used internally are also available as a standalone import, for composing into your own `labelText`/`formatValue` functions: + +```tsx +import { relativeTime } from "public-widget-sdk/formatters"; +``` + +| Export | Signature | Description | +| -------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | +| `relativeTime` | `(timestamp: number, locale?: string) => string` | Converts a timestamp into a human-relative string (`"5 minutes ago"`). Accepts seconds or milliseconds. | + #### Sizing `width` / `height` / `minWidth` / `maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole `styles`/theme system: @@ -266,10 +398,10 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve Whether you pass `height` changes how the card behaves β€” this is intentional, not a quirk: -| | Behavior | -|---|---| -| **`height` omitted** | The card **auto-grows** to fit its content. If `formatValue`/`labelText` produce long text that wraps, the card simply becomes taller. Sizing scales with **width only**. | -| **`height` passed** | The card becomes a **fixed-size box**. Sizing scales with **both width and height** (see [Responsive sizing](#responsive-sizing)). If content is too tall to fit (e.g. a long wrapped value at a small height), it is **clipped**, not overflowed β€” the card will not grow past the height you gave it. | +| | Behavior | +| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **`height` omitted** | The card **auto-grows** to fit its content. If `formatValue`/`labelText` produce long text that wraps, the card simply becomes taller. Sizing scales with **width only**. | +| **`height` passed** | The card becomes a **fixed-size box**. Sizing scales with **both width and height** (see [Responsive sizing](#responsive-sizing)). If content is too tall to fit (e.g. a long wrapped value at a small height), it is **clipped**, not overflowed β€” the card will not grow past the height you gave it. | ```jsx // Auto-height: card grows to fit content, whatever that content turns out to be @@ -309,7 +441,7 @@ If you provide your own font-size utility for a slot, you're opting out of the d ```tsx ``` @@ -330,10 +462,10 @@ Neither state currently accepts style overrides via `styles` β€” flag it if you #### Other props -| Prop | Type | Description | -|---|---|---| -| `title` | `string` | Card title. Default: `"Latest Value"` | -| `unit` | `string` | Unit suffix shown next to the value | +| Prop | Type | Description | +| --------------- | -------- | ---------------------------------------------------------------------------------- | +| `title` | `string` | Card title. Default: `"Latest Value"` | +| `unit` | `string` | Unit suffix shown next to the value | | `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | --- @@ -350,4 +482,4 @@ import "public-widget-sdk/styles.css"; That's the entire integration on your end. No `content` glob changes to your `tailwind.config`, no build coordination, nothing else required β€” every widget in this SDK will render fully styled as soon as this import is present. -> **If styles aren't appearing:** double-check the import path matches your installed package name exactly, and that it's imported somewhere that actually runs before your widgets render (e.g. not inside a conditionally-loaded file). If you're using a bundler with strict CSS module resolution, confirm it supports subpath imports from `node_modules` (most modern bundlers β€” Vite, Webpack 5+, Next.js β€” do, out of the box). \ No newline at end of file +> **If styles aren't appearing:** double-check the import path matches your installed package name exactly, and that it's imported somewhere that actually runs before your widgets render (e.g. not inside a conditionally-loaded file). If you're using a bundler with strict CSS module resolution, confirm it supports subpath imports from `node_modules` (most modern bundlers β€” Vite, Webpack 5+, Next.js β€” do, out of the box). diff --git a/package.json b/package.json index 94a76f88..7fcc64e8 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,14 @@ "exports": { ".": { "import": "./dist/index.mjs", - "require": "./dist/index.js" + "require": "./dist/index.cjs" }, - "./styles.css": "./dist/styles.css" + "./styles.css": "./dist/styles.css", + "./formatters": { + "import": "./dist/formatters.mjs", + "require": "./dist/formatters.cjs", + "types": "./dist/formatters.d.mts" + } }, "scripts": { "clean": "rm -rf dist", diff --git a/src/common.ts b/src/common.ts index 9a5581e8..9df00e97 100644 --- a/src/common.ts +++ b/src/common.ts @@ -49,4 +49,20 @@ theme?: WidgetTheme | BuiltInTheme; minHeight?: number; maxHeight?: number; aspectRatio?: number; -} \ No newline at end of file +} + +export type FormatPreset = + | "number" // thousands separators, locale-aware + | "bytes" // auto-scales B/KB/MB/GB + | "duration" // seconds -> "2h 15m 30s" + | "length" // auto-scales mm/cm/m/km + | "volume" // auto-scales mL/L + | "dataRate" // auto-scales bps/Kbps/Mbps + | "percent"; + +export interface FormatOptions { + locale?: string; // BCP 47 tag, e.g. "en-IN" β€” defaults to browser locale + binary?: boolean; // bytes only: 1024-based (KiB/MiB) vs 1000-based (KB/MB) + precision?: number; // decimal places for the scaled number +} +export type FormatResult = { value: string; unit?: string }; \ No newline at end of file diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 4b0b0238..43556543 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -1,6 +1,11 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; -import { AnedyaWidgetBaseProps } from "../common"; +import { + AnedyaWidgetBaseProps, + FormatOptions, + FormatPreset, + LabelFormatPreset, +} from "../common"; import { SlotClassNames, WidgetTheme } from "../types/root"; import { @@ -8,6 +13,7 @@ import { darkTheme, lightTheme, } from "../themes/defaultTheme"; +import { FORMATTERS, LABEL_FORMATTERS } from "../helpers/formatters"; export type CardSlot = "container" | "title" | "value" | "unit" | "label"; @@ -17,15 +23,18 @@ export interface CardData { timestamp: number; } export type CardWidgetUpdate = Partial< - Omit< - CardWidgetProps, - "node" | "variable" | "onDataChange" - > + Omit >; export interface CardWidgetProps extends AnedyaWidgetBaseProps { unit?: string; /** Decimal places for the displayed value. Omit to show the raw value as-is. */ decimalPlaces?: number; + /** + * Full custom formatting function β€” receives the raw fetched value, + * returns the exact string to display. + * + * Takes precedence over both `format` and `decimalPlaces`. + */ formatValue?: (value: number) => string; /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ labelText?: (timestamp: number) => string; @@ -68,10 +77,30 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * }} */ onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; + + /** + * Named formatting preset for common unit types β€” auto-scales both + * the displayed number and its unit (e.g. `"bytes"` turns `500000` + * into `"500"` + `"KB"`). + * + * When set, this overrides the `unit` prop β€” the preset determines + * its own unit per value. + * + * Ignored if `formatValue` is also provided. + */ + format?: FormatPreset; + /** Options for the active `format` preset β€” e.g. `{ precision: 2, locale: "en-IN" }`. */ + formatOptions?: FormatOptions; + /** + * Named preset for the last-updated label's format. Ignored if + * `labelText` is also provided (which always takes precedence). + * Defaults to `"time"`, matching the widget's previous fixed behavior. + */ + labelFormat?: LabelFormatPreset; } const DEFAULT_WIDTH = 240; -const DEFAULT_HEIGHT = 160; +const DEFAULT_HEIGHT = 160; const DEFAULT_MIN_WIDTH = 180; const DEFAULT_MAX_WIDTH = 480; @@ -92,7 +121,10 @@ export function CardWidget({ height, minWidth = DEFAULT_MIN_WIDTH, maxWidth = DEFAULT_MAX_WIDTH, -}: CardWidgetProps): React.JSX.Element { + format, + formatOptions, + labelFormat, +}: CardWidgetProps): React.JSX.Element { const [value, setValue] = useState(null); const [timestamp, setTimestamp] = useState(null); const [loading, setLoading] = useState(false); @@ -167,12 +199,15 @@ export function CardWidget({ formatValue, labelText, width: width ?? DEFAULT_WIDTH, -// height: height ?? DEFAULT_HEIGHT, -height, + // height: height ?? DEFAULT_HEIGHT, + height, minWidth, maxWidth, className, theme, + format, + formatOptions, + labelFormat, ...dynamicProps, styles: { @@ -203,99 +238,126 @@ height, resolvedProps.styles[slot], ); - const displayValue = useMemo(() => { - if (value == null) return null; + const { displayValue, displayUnit } = useMemo(() => { + if (value == null) + return { displayValue: null, displayUnit: resolvedProps.unit }; - if (resolvedProps.formatValue) return resolvedProps.formatValue(value); + if (resolvedProps.formatValue) { + return { + displayValue: resolvedProps.formatValue(value), + displayUnit: resolvedProps.unit, + }; + } - if (resolvedProps.decimalPlaces != null) - return value.toFixed(resolvedProps.decimalPlaces); + if (resolvedProps.format) { + const result = FORMATTERS[resolvedProps.format]( + value, + resolvedProps.formatOptions, + ); + return { displayValue: result.value, displayUnit: result.unit }; + } + + if (resolvedProps.decimalPlaces != null) { + return { + displayValue: value.toFixed(resolvedProps.decimalPlaces), + displayUnit: resolvedProps.unit, + }; + } - return String(value); - }, [value, resolvedProps.formatValue, resolvedProps.decimalPlaces]); + return { displayValue: String(value), displayUnit: resolvedProps.unit }; + }, [ + value, + resolvedProps.formatValue, + resolvedProps.format, + resolvedProps.formatOptions, + resolvedProps.decimalPlaces, + resolvedProps.unit, + ]); const displayLabel = useMemo(() => { if (timestamp == null) return null; if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); - const d = - timestamp < 1e12 ? new Date(timestamp * 1000) : new Date(timestamp); + const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; + return formatter(timestamp, resolvedProps.formatOptions?.locale); + }, [ + timestamp, + resolvedProps.labelText, + resolvedProps.labelFormat, + resolvedProps.formatOptions?.locale, + ]); + const hasExplicitHeight = height != null || dynamicProps.height != null; - return `Updated ${d.toLocaleTimeString()}`; - }, [timestamp, resolvedProps.labelText]); - - const hasExplicitHeight = height != null || dynamicProps.height != null; - return (

-
- - {resolvedProps.title} - - - {loading ? ( -
- {/* Value Skeleton: Uses the exact font-size variable as its height */} -
- - {/* Label Skeleton: Uses the exact label-size variable as its height */} -
-
- ) : error ? ( - {error} - ) : ( - <> - - - {displayValue} - - {resolvedProps.unit && ( - - {resolvedProps.unit} - - )} - - {displayLabel && ( +
+ {resolvedProps.title} + + {loading ? ( +
+ {/* Value Skeleton: Uses the exact font-size variable as its height */} +
+ + {/* Label Skeleton: Uses the exact label-size variable as its height */} +
+
+ ) : error ? ( + {error} + ) : ( + <> - {displayLabel} + {displayValue} + + {displayUnit && ( + {displayUnit} + )} - )} - - )} + {displayLabel && ( + {displayLabel} + )} + + )} +
-
); } diff --git a/src/helpers/formatters.ts b/src/helpers/formatters.ts new file mode 100644 index 00000000..eb927868 --- /dev/null +++ b/src/helpers/formatters.ts @@ -0,0 +1,132 @@ +import { FormatOptions, FormatPreset, FormatResult, LabelFormatPreset } from "../common"; + +function formatBytes(raw: number, { binary = false, precision = 1, locale }: FormatOptions = {}): FormatResult { + const base = binary ? 1024 : 1000; + const units = binary + ? ["B", "KiB", "MiB", "GiB", "TiB"] + : ["B", "KB", "MB", "GB", "TB"]; + + let scaled = raw; + let i = 0; + while (Math.abs(scaled) >= base && i < units.length - 1) { + scaled /= base; + i++; + } + + return { + value: new Intl.NumberFormat(locale, { maximumFractionDigits: precision }).format(scaled), + unit: units[i], + }; +} + +function formatDuration(seconds: number): FormatResult { + const units: [string, number][] = [["d", 86400], ["h", 3600], ["m", 60], ["s", 1]]; + let remaining = Math.floor(seconds); + const parts: string[] = []; + + for (const [label, size] of units) { + if (remaining >= size) { + const count = Math.floor(remaining / size); + parts.push(`${count}${label}`); + remaining %= size; + } + } + + return { value: parts.length ? parts.join(" ") : "0s" }; +} + +function formatNumber(raw: number, { locale, precision }: FormatOptions = {}): FormatResult { + return { + value: new Intl.NumberFormat(locale, { + maximumFractionDigits: precision ?? 2, + }).format(raw), + }; +} + +// length / volume / dataRate can all reuse the same scaling shape as formatBytes, +// just with a different `units` array and `base` β€” e.g.: +function formatLength(raw: number, { precision = 1, locale }: FormatOptions = {}): FormatResult { + const units: [string, number][] = [["km", 1000], ["m", 1], ["cm", 0.01], ["mm", 0.001]]; + const [unit, factor] = units.find(([, f]) => Math.abs(raw) >= f) ?? units[units.length - 1]; + return { + value: new Intl.NumberFormat(locale, { maximumFractionDigits: precision }).format(raw / factor), + unit, + }; +} + +export const FORMATTERS: Record FormatResult> = { + /** Locale-aware thousands separators, e.g. 123456 -> "123,456". */ + number: formatNumber, + /** Auto-scales bytes to the largest sensible unit: B / KB / MB / GB / TB (or KiB/MiB/GiB with `binary: true`). */ + bytes: formatBytes, + /** Converts seconds into a compact duration string, e.g. 9000 -> "2h 30m". */ + duration: formatDuration, + /** Auto-scales meters to the largest sensible unit: mm / cm / m / km. */ + length: formatLength, + /** Auto-scales milliliters to the largest sensible unit: mL / L. */ + volume: (raw, opts) => formatLength(raw, opts), + /** Auto-scales bits-per-second to the largest sensible unit: bps / Kbps / Mbps. */ + dataRate: (raw, opts) => formatBytes(raw, opts), + /** Formats a 0–100 number as a percentage string, e.g. 45 -> "45%". */ + percent: (raw, { precision, locale } = {}) => ({ + value: new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: precision ?? 1 }).format(raw / 100), + }), +}; + + + +/** + * Formats a timestamp as a human-relative string (e.g. "5 minutes ago", + * "2 hours ago", "just now") instead of a fixed clock time. + * + * Accepts timestamps in either seconds or milliseconds β€” values below + * 1e12 are assumed to be seconds and converted automatically. + */ +export function relativeTime(timestamp: number, locale?: string): string { + const ms = timestamp < 1e12 ? timestamp * 1000 : timestamp; + const diffSeconds = Math.round((ms - Date.now()) / 1000); + + const divisions: [Intl.RelativeTimeFormatUnit, number][] = [ + ["year", 60 * 60 * 24 * 365], + ["month", 60 * 60 * 24 * 30], + ["day", 60 * 60 * 24], + ["hour", 60 * 60], + ["minute", 60], + ["second", 1], + ]; + + const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" }); + + for (const [unit, secondsInUnit] of divisions) { + if (Math.abs(diffSeconds) >= secondsInUnit || unit === "second") { + return rtf.format(Math.round(diffSeconds / secondsInUnit), unit); + } + } + + return rtf.format(0, "second"); +} + +export const LABEL_FORMATTERS: Record string> = { + /** Locale time only, e.g. "14:32:10" */ + time: (ts, locale) => { + const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); + return `Updated ${d.toLocaleTimeString(locale)}`; + }, + /** Locale date only, e.g. "7/24/2026" */ + date: (ts, locale) => { + const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); + return `Updated ${d.toLocaleDateString(locale)}`; + }, + /** Locale date + time, e.g. "7/24/2026, 2:32:10 PM" */ + datetime: (ts, locale) => { + const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); + return `Updated ${d.toLocaleString(locale)}`; + }, + /** Human-relative, e.g. "5 minutes ago" */ + relative: (ts, locale) => relativeTime(ts, locale), + /** Raw ISO 8601 string, e.g. "2026-07-24T14:32:10.000Z" β€” useful for logs/debugging */ + iso: (ts) => { + const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); + return d.toISOString(); + }, +}; \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 4082c4d0..55d8b8ab 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -8,7 +8,7 @@ import { CardWidget } from "public-widget-sdk"; // Import your stylesheet via the industry-standard subpath import "public-widget-sdk/styles.css"; - +import { relativeTime } from "public-widget-sdk/formatters"; @@ -40,12 +40,16 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
+
{/* ============================================================ * 1. Default appearance β€” no theme, no styles, no * formatting props. Every fallback in the widget in one place. * ============================================================ */} - + `Last synced ${relativeTime(ts)}`} + + /> {/* ============================================================ diff --git a/tsdown.config.ts b/tsdown.config.ts index ea6b6752..78e61558 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -1,7 +1,10 @@ import { defineConfig } from "tsdown"; export default defineConfig({ - entry: ["src/index.ts"], + entry: { + index: "src/index.ts", + formatters: "src/helpers/formatters.ts", + }, format: ["esm", "cjs"], dts: true, tsconfig: "./ts.config.json", From cd33dfd8d79dc13659866a58763b62db17a1511e Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Fri, 24 Jul 2026 09:58:07 +0530 Subject: [PATCH 31/66] build error fix --- src/common.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common.ts b/src/common.ts index 9df00e97..685b5297 100644 --- a/src/common.ts +++ b/src/common.ts @@ -65,4 +65,6 @@ export interface FormatOptions { binary?: boolean; // bytes only: 1024-based (KiB/MiB) vs 1000-based (KB/MB) precision?: number; // decimal places for the scaled number } -export type FormatResult = { value: string; unit?: string }; \ No newline at end of file +export type FormatResult = { value: string; unit?: string }; + +export type LabelFormatPreset = "time" | "date" | "datetime" | "relative" | "iso"; \ No newline at end of file From befd8ae5cb286e85029deefc37ec7343477c755f Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 10:55:22 +0530 Subject: [PATCH 32/66] added basic gauge chart widget --- dist/style.css | 2 +- .../GaugeChart/GaugeChartWidget.tsx | 1312 ++++++++++------- src/hooks/useResizeObserver.ts | 48 +- src/styles/base.css | 73 +- src/themes/gaugeTheme.ts | 94 +- src/types/gauge.ts | 113 ++ test/my-app/src/App.jsx | 172 ++- 7 files changed, 1141 insertions(+), 673 deletions(-) create mode 100644 src/types/gauge.ts diff --git a/dist/style.css b/dist/style.css index 5d136a33..70000fcf 100644 --- a/dist/style.css +++ b/dist/style.css @@ -1,2 +1,2 @@ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:0}.top-0{top:0}.left-0{left:0}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.block{display:block}.contents{display:contents}.flex{display:flex}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-full{height:100%}.w-full{width:100%}.shrink{flex-shrink:1}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.gap-\[var\(--anedya-gauge-gap\)\]{gap:var(--anedya-gauge-gap)}.rounded{border-radius:.25rem}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.\[fill\:var\(--anedya-gauge-bar-fill\)\]{fill:var(--anedya-gauge-bar-fill)}.\[fill\:var\(--anedya-gauge-needle-color\)\]{fill:var(--anedya-gauge-needle-color)}.\[fill\:var\(--anedya-gauge-track-fill\)\]{fill:var(--anedya-gauge-track-fill)}.fill-\[var\(--anedya-gauge-tick-label-color\)\]{fill:var(--anedya-gauge-tick-label-color)}.fill-slate-400{fill:var(--color-slate-400)}.fill-slate-500{fill:var(--color-slate-500)}.\[stroke\:var\(--anedya-gauge-bar-stroke\)\]{stroke:var(--anedya-gauge-bar-stroke)}.\[stroke\:var\(--anedya-gauge-needle-color\)\]{stroke:var(--anedya-gauge-needle-color)}.\[stroke\:var\(--anedya-gauge-segment-stroke\)\]{stroke:var(--anedya-gauge-segment-stroke)}.\[stroke\:var\(--anedya-gauge-tick-stroke\)\]{stroke:var(--anedya-gauge-tick-stroke)}.\[stroke\:var\(--anedya-gauge-track-stroke\)\]{stroke:var(--anedya-gauge-track-stroke)}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.p-\[var\(--anedya-gauge-padding\)\]{padding:var(--anedya-gauge-padding)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.text-\[length\:var\(--anedya-gauge-center-value-size\)\]{font-size:var(--anedya-gauge-center-value-size)}.text-\[length\:var\(--anedya-gauge-needle-label-size\)\]{font-size:var(--anedya-gauge-needle-label-size)}.text-\[length\:var\(--anedya-gauge-tick-label-size\)\]{font-size:var(--anedya-gauge-tick-label-size)}.text-\[length\:var\(--anedya-gauge-title-size\)\]{font-size:var(--anedya-gauge-title-size)}.font-\[var\(--anedya-gauge-center-value-weight\)\]{--tw-font-weight:var(--anedya-gauge-center-value-weight);font-weight:var(--anedya-gauge-center-value-weight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-\[var\(--anedya-gauge-center-value-color\)\]{color:var(--anedya-gauge-center-value-color)}.text-\[var\(--anedya-gauge-needle-label-color\)\]{color:var(--anedya-gauge-needle-label-color)}.text-\[var\(--anedya-gauge-tick-label-color\)\]{color:var(--anedya-gauge-tick-label-color)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}.anedya-gauge{--anedya-gauge-padding:1rem;--anedya-gauge-title-size:.875rem;--anedya-gauge-track-stroke:#e2e8f0;--anedya-gauge-track-fill:transparent;--anedya-gauge-bar-stroke:#3b82f6;--anedya-gauge-bar-fill:transparent;--anedya-gauge-thickness:12;--anedya-gauge-needle-color:#334155;--anedya-gauge-needle-cap-color:#334155;--anedya-gauge-center-value-size:2rem;--anedya-gauge-center-value-weight:700;--anedya-gauge-center-value-color:#1e293b;--anedya-gauge-needle-label-size:.75rem;--anedya-gauge-needle-label-color:#64748b;--anedya-gauge-tick-stroke:#94a3b8;--anedya-gauge-tick-label-size:.625rem;--anedya-gauge-tick-label-color:#64748b;--anedya-gauge-segment-stroke:#e2e8f0;--anedya-gauge-gap:.5rem;container:anedya-gauge/inline-size}@container anedya-gauge(min-width: 280px){.anedya-gauge{--anedya-gauge-title-size:.9375rem;--anedya-gauge-center-value-size:2.25rem;--anedya-gauge-needle-label-size:.8125rem;--anedya-gauge-tick-label-size:.6875rem}}@container anedya-gauge(min-width: 400px){.anedya-gauge{--anedya-gauge-title-size:1.0625rem;--anedya-gauge-center-value-size:2.75rem;--anedya-gauge-needle-label-size:.875rem;--anedya-gauge-tick-label-size:.75rem}}@container anedya-gauge(min-width: 560px){.anedya-gauge{--anedya-gauge-title-size:1.1875rem;--anedya-gauge-center-value-size:3.25rem;--anedya-gauge-needle-label-size:1rem;--anedya-gauge-tick-label-size:.875rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-indigo-400:oklch(67.3% .182 276.935);--color-indigo-500:oklch(58.5% .233 277.117);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-md:.375rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.z-10{z-index:10}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mt-2{margin-top:calc(var(--spacing) * -2)}.block{display:block}.contents{display:contents}.flex{display:flex}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-auto{height:auto}.w-full{width:100%}.shrink{flex-shrink:1}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.gap-\[var\(--anedya-gauge-gap\)\]{gap:var(--anedya-gauge-gap)}.rounded{border-radius:.25rem}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.fill-current{fill:currentColor}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.p-\[var\(--anedya-gauge-padding\)\]{padding:var(--anedya-gauge-padding)}.px-2{padding-inline:calc(var(--spacing) * 2)}.py-1{padding-block:var(--spacing)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.text-\[length\:var\(--anedya-gauge-label-size\)\]{font-size:var(--anedya-gauge-label-size)}.text-\[length\:var\(--anedya-gauge-tick-size\)\]{font-size:var(--anedya-gauge-tick-size)}.text-\[length\:var\(--anedya-gauge-title-size\)\]{font-size:var(--anedya-gauge-title-size)}.text-\[length\:var\(--anedya-gauge-unit-size\)\]{font-size:var(--anedya-gauge-unit-size)}.text-\[length\:var\(--anedya-gauge-value-size\)\]{font-size:var(--anedya-gauge-value-size)}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-indigo-400{color:var(--color-indigo-400)}.text-indigo-500{color:var(--color-indigo-500)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}.anedya-gauge{--anedya-gauge-padding:.75rem;--anedya-gauge-gap:.25rem;--anedya-gauge-title-size:.875rem;--anedya-gauge-value-size:1.75rem;--anedya-gauge-unit-size:.875rem;--anedya-gauge-label-size:.75rem;--anedya-gauge-tick-size:.625rem;container:anedya-gauge/inline-size}@container anedya-gauge (min-width:260px){.anedya-gauge{--anedya-gauge-padding:1rem;--anedya-gauge-value-size:2.25rem;--anedya-gauge-unit-size:1rem;--anedya-gauge-label-size:.875rem;--anedya-gauge-tick-size:.75rem}}@container anedya-gauge (min-width:380px){.anedya-gauge{--anedya-gauge-padding:1.25rem;--anedya-gauge-title-size:1rem;--anedya-gauge-value-size:3rem;--anedya-gauge-unit-size:1.125rem;--anedya-gauge-label-size:1rem;--anedya-gauge-tick-size:.8125rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} \ No newline at end of file diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index 6aa8f4da..63e74e65 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -1,664 +1,872 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import { twMerge } from "tailwind-merge"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import * as d3 from "d3"; -import {SlotClassNames, WidgetTheme } from "../../types/root"; +import { twMerge } from "tailwind-merge"; import { AnedyaWidgetBaseProps } from "../../common"; +import { SlotClassNames, WidgetTheme } from "../../types/root"; import { - GAUGE_DEFAULT_CLASSES, - gaugeThemes, + GaugeAnimationConfig, + GaugeArcConfig, + GaugeBarSpec, + GaugeColor, + GaugeLabelsConfig, + GaugeNeedleConfig, + GaugeNeedleLabelConfig, + GaugeScaleConfig, + GaugeSegment, GaugeSlot, + GaugeThreshold, + GaugeTicksConfig, + GaugeTooltipConfig, + GaugeTrackConfig, + GaugeValueLabelConfig, + GaugeVariant, +} from "../../types/gauge"; +import { + DEFAULT_GAUGE_THEME, + GAUGE_DEFAULT_CLASSES, + gaugeDarkTheme, + gaugeLightTheme, } from "../../themes/gaugeTheme"; import { useResizeObserver } from "../../hooks/useResizeObserver"; export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { - variant?: "progress" | "needle" | "segmented" | "multiBar"; + variant?: GaugeVariant; + /** Used before live data arrives, or standalone in dummy-data mode. */ value?: number; - min?: number; max?: number; size?: number; + responsive?: boolean; - arc?: { - startAngle?: number; // degrees, default 180 - endAngle?: number; // degrees, default 0 (semi-circle left to right) - thickness?: number; - cornerRadius?: number; - gap?: number; - }; - - track?: { - show?: boolean; - color?: string; - }; - + arc?: GaugeArcConfig; + track?: GaugeTrackConfig; fillMode?: "progress" | "solid"; + /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ + color?: GaugeColor; + bars?: GaugeBarSpec[]; + + needle?: GaugeNeedleConfig; + labels?: GaugeLabelsConfig; + valueLabel?: GaugeValueLabelConfig; + needleLabel?: GaugeNeedleLabelConfig; + scale?: GaugeScaleConfig; + ticks?: GaugeTicksConfig; + segments?: GaugeSegment[]; + thresholds?: GaugeThreshold[]; + animation?: GaugeAnimationConfig; + tooltip?: GaugeTooltipConfig; - bars?: Array<{ - value: number; - color?: string; - label?: string; - }>; - - needle?: { - show?: boolean; - type?: "line" | "rounded" | "drop" | "triangle"; - length?: "short" | "medium" | "full" | number; - width?: number; - color?: string; - capRadius?: number; - animation?: boolean; - }; - - valueLabel?: { - show?: boolean; - precision?: number; - prefix?: string; - suffix?: string; - formatter?: (value: number) => string; - }; - - needleLabel?: { - show?: boolean; - formatter?: (value: number) => string; - }; - - scale?: { - minLabel?: string; - maxLabel?: string; - }; + classNames?: SlotClassNames; + style?: React.CSSProperties; - ticks?: { - show?: boolean; - count?: number; - position?: "inside" | "outside" | "cross"; - length?: number; - labels?: boolean; - }; + onClick?: (value: number) => void; + onHover?: (value: number | null) => void; + onValueChange?: (value: number) => void; +} - segments?: Array<{ - from: number; - to: number; - color: string; - }>; +const DEG2RAD = Math.PI / 180; - thresholds?: Array<{ - value: number; - color: string; - }>; +const DEFAULT_ARC: Required> = { + startAngle: -90, + endAngle: 90, + cornerRadius: 0, + gap: 6, +}; - gradient?: { - colors: string[]; - }; +const DEFAULT_ANIMATION: Required = { + duration: 750, + easing: "easeCubicOut", +}; - animation?: { - duration?: number; - easing?: string; - }; +function resolveEase(name: string) { + return (d3 as any)[name] ?? d3.easeCubicOut; +} - tooltip?: { - show?: boolean; - }; +function needlePixelLength( + length: GaugeNeedleConfig["length"], + radius: number +) { + if (typeof length === "number") return length; + switch (length) { + case "short": + return radius * 0.55; + case "full": + return radius * 0.95; + case "medium": + default: + return radius * 0.75; + } +} - onClick?: () => void; - onHover?: (isHover: boolean) => void; - onValueChange?: (value: number) => void; +/** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ +function needleShape( + type: NonNullable, + length: number, + width: number +) { + const w = width; + switch (type) { + case "line": + return { + tag: "line", + attrs: { + x1: 0, + y1: 0, + x2: 0, + y2: -length, + strokeWidth: w, + strokeLinecap: "butt", + }, + }; + case "rounded": + return { + tag: "line", + attrs: { + x1: 0, + y1: 0, + x2: 0, + y2: -length, + strokeWidth: w, + strokeLinecap: "round", + }, + }; + case "triangle": { + const half = w / 2; + return { + tag: "polygon", + attrs: { + points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ + -length * 0.15 + }`, + }, + }; + } + case "drop": + default: { + const half = w / 2; + // Teardrop: rounded base, sharp tip. + const d = `M ${-half} 0 + C ${-half} ${-length * 0.35}, ${-w} ${ + -length * 0.7 + }, 0 ${-length} + C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 + A ${half} ${half} 0 1 1 ${-half} 0 Z`; + return { tag: "path", attrs: { d } }; + } + } +} - classNames?: SlotClassNames; +function isGradientColor(c?: GaugeColor): c is string[] { + return Array.isArray(c) && c.length >= 2; } -// Helper: convert degrees to radians -const deg2rad = (deg: number) => (deg * Math.PI) / 180; +/** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ +function resolveFill( + defs: d3.Selection, + id: string, + color: GaugeColor | undefined, + fallback: string +): string { + if (!color) return fallback; + if (!isGradientColor(color)) return color; + + let grad = defs.select(`#${id}`); + if (grad.empty()) { + grad = defs.append("linearGradient").attr("id", id); + } + grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); + grad.selectAll("stop").remove(); + color.forEach((c, i) => + grad + .append("stop") + .attr("offset", `${(i / (color.length - 1)) * 100}%`) + .attr("stop-color", c) + ); + return `url(#${id})`; +} -// Default angles for semi-circle (left to right) -const DEFAULT_START_ANGLE = 180; -const DEFAULT_END_ANGLE = 0; +/** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ +function getArcBounds(startDeg: number, endDeg: number) { + const lo = Math.min(startDeg, endDeg); + const hi = Math.max(startDeg, endDeg); + const angles = [startDeg, endDeg]; + for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); + + let minX = Infinity, + maxX = -Infinity, + minY = Infinity, + maxY = -Infinity; + angles.forEach((deg) => { + const a = deg * DEG2RAD; + const x = Math.sin(a); + const y = -Math.cos(a); + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + }); + return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; +} export function GaugeWidget({ node, variable, - value: valueOverride, title, + theme, + className, + style, + width, + height, + minWidth = 160, + maxWidth = 480, + minHeight = 160, + maxHeight = 480, + aspectRatio, + variant = "progress", + value: valueProp, min = 0, max = 100, size, - arc: arcProps = {}, - track: trackProps = {}, + responsive = true, + + arc, + track, fillMode = "progress", + color, bars, - needle: needleProps = {}, - valueLabel: valueLabelProps = {}, - needleLabel: needleLabelProps = {}, - scale: scaleProps = {}, - ticks: ticksProps = {}, + + needle, + labels, + valueLabel, + needleLabel, + scale, + ticks, segments, thresholds, - gradient, animation, tooltip, + + classNames = {}, onClick, onHover, onValueChange, - classNames = {}, - theme, - className, - width: initialWidth, - height: initialHeight, - minWidth, - maxWidth, }: GaugeWidgetProps) { - const containerRef = useRef(null); const svgRef = useRef(null); + const tooltipRef = useRef(null); + const prevValueRef = useRef(min); - // ----- Data fetching (same as CardWidget) ----- const [fetchedValue, setFetchedValue] = useState(null); - const [fetchedTimestamp, setFetchedTimestamp] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const mountedRef = useRef(false); + const [hoverValue, setHoverValue] = useState(null); + // ---- Live data fetch (mirrors CardWidget) ---- useEffect(() => { if (!node) return; - mountedRef.current = true; - const fetchLatest = async () => { - setLoading(true); - setError(null); - try { - const res = await node.getLatestData(variable); - if (!mountedRef.current) return; - if (res.isSuccess && res.isDataAvailable) { + let mounted = true; + + node + .getLatestData(variable) + .then((res: any) => { + if (!mounted) return; + if (res?.isSuccess && res?.isDataAvailable) { setFetchedValue(res.data.value); - setFetchedTimestamp(res.data.timestamp); - } else { - setFetchedValue(null); - setError(res.error?.errorMessage ?? "No data available"); } - } catch (err: any) { - if (!mountedRef.current) return; - setFetchedValue(null); - setError(err?.message ?? "Failed to fetch data"); - } finally { - if (mountedRef.current) { - setLoading(false); - } - } - }; - fetchLatest(); + }) + .catch(() => { + /* fall back to `value` prop / dummy data silently */ + }); + return () => { - mountedRef.current = false; + mounted = false; }; }, [node, variable]); - // Resolve displayed value - const value = valueOverride ?? fetchedValue; + const rawValue = fetchedValue ?? valueProp ?? min; + const clampedValue = Math.min(max, Math.max(min, rawValue)); - // ----- Dynamic overrides (like onDataChange in Card) ----- - const [dynamicProps, setDynamicProps] = useState>({}); useEffect(() => { - if (onValueChange) { - onValueChange(value ?? 0); - } - }, [value, onValueChange]); + onValueChange?.(clampedValue); + }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps - // We can support an onDataChange like callback if desired; for now keep simple + // ---- Responsive sizing ---- + const { ref: wrapperRef, size: dims } = useResizeObserver( + responsive && size == null + ); - // Merge all props (original + dynamic) - const resolvedProps = { - ...({ - variant, - min, - max, - arc: arcProps, - track: trackProps, - fillMode, - bars, - needle: needleProps, - valueLabel: valueLabelProps, - needleLabel: needleLabelProps, - scale: scaleProps, - ticks: ticksProps, - segments, - thresholds, - gradient, - animation, - tooltip, - } as GaugeWidgetProps), - ...dynamicProps, - classNames: { - ...classNames, - ...(dynamicProps.classNames ?? {}), - }, + // ---- Resolved config (defaults per variant) ---- + const resolvedArc = { ...DEFAULT_ARC, ...arc }; + const resolvedTrack: Required = { + show: track?.show ?? true, + color: track?.color ?? "", + }; + const needleShownByDefault = variant === "progress" || variant === "needle"; + const resolvedNeedle: Required> & { + length: NonNullable; + } = { + show: needle?.show ?? needleShownByDefault, + type: needle?.type ?? "rounded", + length: needle?.length ?? "medium", + width: needle?.width ?? 4, + color: needle?.color ?? "", + capRadius: needle?.capRadius ?? 6, + animation: needle?.animation ?? true, + }; + const resolvedLabels: Required = { + show: labels?.show ?? true, + position: labels?.position ?? "outside", + }; + const resolvedValueLabel: Required< + Omit + > & { formatter?: (v: number) => string } = { + show: valueLabel?.show ?? true, + precision: valueLabel?.precision ?? 0, + prefix: valueLabel?.prefix ?? "", + suffix: valueLabel?.suffix ?? "", + formatter: valueLabel?.formatter, + }; + + const resolvedNeedleLabel: Required< + Omit + > & { formatter?: (v: number) => string } = { + show: needleLabel?.show ?? false, + formatter: needleLabel?.formatter, + }; + const resolvedTicks: Required = { + show: ticks?.show ?? (variant === "needle" || variant === "segmented"), + count: ticks?.count ?? 5, + position: ticks?.position ?? "outside", + length: ticks?.length ?? 6, + labels: ticks?.labels ?? true, + }; + const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; + const resolvedTooltip: Required = { + show: tooltip?.show ?? true, }; - // Resolve theme + // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- const resolvedTheme: WidgetTheme = theme === "dark" - ? gaugeThemes.dark + ? gaugeDarkTheme : theme === "light" - ? gaugeThemes.light - : (theme as WidgetTheme) ?? gaugeThemes.light; - - // Slot resolution (lowest to highest precedence) - const resolveSlot = (slot: GaugeSlot) => - twMerge( - GAUGE_DEFAULT_CLASSES[slot], - resolvedTheme.classNames[slot], - resolvedProps.classNames?.[slot], - ); - - // ----- Resize observer for dynamic SVG size ----- - const { ref: gaugeContainerRef, width: containerWidth, height: containerHeight } = - useResizeObserver(); + ? gaugeLightTheme + : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; + + const resolveSlot = useCallback( + (slot: GaugeSlot) => + twMerge( + GAUGE_DEFAULT_CLASSES[slot], + resolvedTheme.classNames[slot], + classNames[slot] + ), + [resolvedTheme, classNames] + ); - // Combine refs: containerRef for our own use, resizeRef for observer - const setContainerRef = (node: HTMLDivElement | null) => { - containerRef.current = node; - (resizeRef as any)(node); - }; + const boxWidth = size ?? width ?? (dims.width || 240); + const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); - // Final dimensions (shorthand size overrides width/height) - const effectiveWidth = size ?? initialWidth ?? containerWidth; - const effectiveHeight = size ?? initialHeight ?? containerHeight; - - // ----- Arc configuration ----- - const startAngleDeg = arcProps.startAngle ?? DEFAULT_START_ANGLE; - const endAngleDeg = arcProps.endAngle ?? DEFAULT_END_ANGLE; - const thickness = arcProps.thickness ?? 12; - const cornerRadius = arcProps.cornerRadius ?? 0; - const gap = arcProps.gap ?? 2; - - // Convert to radians for D3 - const startAngleRad = deg2rad(startAngleDeg); - const endAngleRad = deg2rad(endAngleDeg); - - // Compute angle for a given value - const valueToAngle = (val: number) => { - const clamped = Math.min(max, Math.max(min, val)); - const ratio = (clamped - min) / (max - min); - return startAngleRad + ratio * (endAngleRad - startAngleRad); - }; + const bounds = useMemo( + () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), + [resolvedArc.startAngle, resolvedArc.endAngle] + ); - // D3 arc generator - const createArc = (innerRadius: number, outerRadius: number) => - d3.arc() - .innerRadius(innerRadius) - .outerRadius(outerRadius) - .startAngle(startAngleRad) - .endAngle(endAngleRad) - .cornerRadius(cornerRadius); + const pad = 8; + // Reserve room below the arc for value/needle-label/variable text so + // the dome never gets crowded β€” bigger reserve when the value label is on. + const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + const availW = boxWidth - pad * 2; + const availH = boxHeight * (1 - textReserve) - pad * 2; + + const outerRadius = + resolvedArc.radius ?? + Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); + + const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); + + // Center the arc's bounding box within the available width, anchor its top at `pad`. + const cx = + pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; + const cy = pad - bounds.minY * outerRadius; + + const angleScale = useMemo( + () => + d3 + .scaleLinear() + .domain([min, max]) + .range([ + resolvedArc.startAngle * DEG2RAD, + resolvedArc.endAngle * DEG2RAD, + ]) + .clamp(true), + [min, max, resolvedArc.startAngle, resolvedArc.endAngle] + ); - // ----- SVG drawing ----- + // ---- D3 draw ---- useEffect(() => { - if (!svgRef.current || !containerRef.current) return; + if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; const svg = d3.select(svgRef.current); - svg.selectAll("*").remove(); // clear previous render - - const w = effectiveWidth; - const h = effectiveHeight; - const cx = w / 2; - const cy = h / 2; - - // Determine arc radii based on available space and thickness - const maxRadius = Math.min(cx, cy) - 10; // padding - const outerRadius = maxRadius; - const innerRadius = outerRadius - thickness; - - // Helper to draw an arc (for track, bar, segments) - const drawArc = ( - selection: d3.Selection, - startAngle: number, - endAngle: number, - innerR: number, - outerR: number, - className?: string, - ) => { - const arcGen = d3.arc() - .innerRadius(innerR) - .outerRadius(outerR) - .startAngle(startAngle) - .endAngle(endAngle) - .cornerRadius(cornerRadius); - selection.attr("d", arcGen as any); - if (className) selection.attr("class", className); - }; - - // ----- Track ----- - if (trackProps.show !== false) { - const trackArc = createArc(innerRadius, outerRadius); - svg.append("path") - .datum({ endAngle: endAngleRad }) - .attr("d", trackArc as any) - .attr("class", resolveSlot("track")) - .attr("fill", "none") - .attr("stroke-width", thickness); + const defs = svg.select("defs"); + const root = svg.select("g.anedya-gauge-root"); + root.attr("transform", `translate(${cx},${cy})`); + + const ease = resolveEase(resolvedAnimation.easing); + const arcGen = d3 + .arc<{ startAngle: number; endAngle: number; r: number }>() + .innerRadius((d) => d.r - thickness) + .outerRadius((d) => d.r) + .cornerRadius(resolvedArc.cornerRadius) + .startAngle((d) => d.startAngle) + .endAngle((d) => d.endAngle); + + const startA = resolvedArc.startAngle * DEG2RAD; + const endA = resolvedArc.endAngle * DEG2RAD; + + // --- Track --- + const trackSel = root.select( + "path.anedya-gauge-track-path" + ); + if (resolvedTrack.show && variant !== "multiBar") { + trackSel + .attr( + "d", + arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! + ) + .attr("fill", resolvedTrack.color || "currentColor") + .attr("opacity", 1); + } else { + trackSel.attr("opacity", 0); } - // ----- Determine bar fill color (from thresholds or single color) ----- - let barColorClass = ""; // we use Tailwind classes for dynamic color via CSS variables? We'll rely on the slot class. - // For simplicity, we let the slot "bar" carry the default stroke color via CSS variable. - // Segments and thresholds add their own inline styles if needed. - // We'll apply colors directly via inline style when needed. - - // ----- Variant: progress bar (single arc) ----- - if (variant === "progress" || variant === "needle" || variant === "segmented") { - const currentAngle = valueToAngle(value ?? min); - const progressArc = d3.arc() - .innerRadius(innerRadius) - .outerRadius(outerRadius) - .startAngle(startAngleRad) - .endAngle(currentAngle) - .cornerRadius(cornerRadius); - - // Handle segments - if (segments && segments.length > 0) { - // Draw segments as separate colored arcs spanning the full range - segments.forEach((seg) => { - const segStart = valueToAngle(seg.from); - const segEnd = valueToAngle(seg.to); - svg.append("path") - .datum({ endAngle: segEnd }) - .attr("d", (d) => { - const arc = d3.arc() - .innerRadius(innerRadius) - .outerRadius(outerRadius) - .startAngle(segStart) - .endAngle(d.endAngle) - .cornerRadius(0); - return arc(d); - }) - .attr("fill", "none") - .attr("stroke", seg.color) - .attr("stroke-width", thickness) - .attr("class", resolveSlot("segment")); - }); - - // If fillMode is progress, we overlay the bar only up to current value using a clip-path? - // We'll just draw the bar on top. - if (fillMode === "progress") { - svg.append("path") - .attr("d", progressArc as any) - .attr("fill", "none") - .attr("stroke", "currentColor") // will be overridden by class - .attr("stroke-width", thickness) - .attr("class", resolveSlot("bar")); - } - } else { - // Standard bar (no segments) - // If thresholds exist, choose color based on current value - let strokeColor = ""; - if (thresholds && thresholds.length > 0) { - const threshold = [...thresholds] - .sort((a, b) => a.value - b.value) - .find(t => (value ?? min) <= t.value) ?? thresholds[thresholds.length - 1]; - strokeColor = threshold.color; - } - - if (fillMode === "solid") { - // Draw a full arc as the bar, with solid color - const fullArc = createArc(innerRadius, outerRadius); - svg.append("path") - .datum({ endAngle: endAngleRad }) - .attr("d", fullArc as any) - .attr("fill", "none") - .attr("stroke", strokeColor || "currentColor") - .attr("stroke-width", thickness) - .attr("class", resolveSlot("bar")); - } else { - // Progress fill - svg.append("path") - .attr("d", progressArc as any) - .attr("fill", "none") - .attr("stroke", strokeColor || "currentColor") - .attr("stroke-width", thickness) - .attr("class", resolveSlot("bar")); + // --- Bar (progress / solid / segmented base) --- + const barGroup = root.select("g.anedya-gauge-bar-group"); + barGroup.selectAll("*").remove(); + + if (variant === "multiBar" && bars?.length) { + const maxBars = bars.slice(0, 10); + maxBars.forEach((bar, i) => { + const r = outerRadius - i * (thickness + resolvedArc.gap); + if (resolvedTrack.show) { + barGroup + .append("path") + .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) + .attr( + "class", + twMerge("anedya-gauge-multibar-track", resolveSlot("track")) + ) + .attr("fill", resolvedTrack.color || "currentColor") + .attr("stroke", "none"); } - } - } - - // ----- Variant: multiBar ----- - if (variant === "multiBar" && bars && bars.length > 0) { - const totalThickness = thickness * bars.length + gap * (bars.length - 1); - const startRadius = outerRadius - totalThickness + thickness; - bars.forEach((bar, i) => { - const barThickness = thickness; // shared - const innerR = startRadius + i * (thickness + gap); - const outerR = innerR + barThickness; - const barAngle = valueToAngle(bar.value); - const barArc = d3.arc() - .innerRadius(innerR) - .outerRadius(outerR) - .startAngle(startAngleRad) - .endAngle(barAngle) - .cornerRadius(cornerRadius); - - svg.append("path") - .attr("d", barArc as any) - .attr("fill", "none") - .attr("stroke", bar.color || "currentColor") - .attr("stroke-width", barThickness) - .attr("class", resolveSlot("bar")); + const valAngle = d3 + .scaleLinear() + .domain([min, max]) + .range([startA, endA]) + .clamp(true)(bar.value); + + const barFill = resolveFill( + defs, + `anedya-gauge-bar-fill-${i}`, + bar.color, + "currentColor" + ); + + const path = barGroup + .append("path") + .attr("class", resolveSlot("bar")) + .attr("fill", barFill) + .attr("stroke", "none"); + path + .datum({ startAngle: startA, endAngle: startA, r }) + .attr("d", arcGen as any) + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("d", function (d: any) { + const i2 = d3.interpolate(d.endAngle, valAngle); + return (t) => { + d.endAngle = i2(t); + return arcGen(d)!; + }; + }); }); - } - - // ----- Needle ----- - const needleShow = needleProps.show !== false && (variant === "needle" || variant === "segmented" || variant === "progress" ? needleProps.show : false); - if (needleShow && value != null) { - const needleAngle = valueToAngle(value); - const needleLength = (() => { - const len = needleProps.length ?? "medium"; - switch (len) { - case "short": return outerRadius * 0.6; - case "medium": return outerRadius * 0.8; - case "full": return outerRadius * 1.05; - default: return len; - } - })(); - const needleWidth = needleProps.width ?? 2; - const capRadius = needleProps.capRadius ?? 4; - const needleColor = needleProps.color ?? "currentColor"; - - // Needle tip coordinates - const tipX = cx + needleLength * Math.cos(needleAngle - Math.PI / 2); - const tipY = cy + needleLength * Math.sin(needleAngle - Math.PI / 2); - - const needleGroup = svg.append("g").attr("class", resolveSlot("needle")); - - // Draw needle line (simple line) - needleGroup.append("line") - .attr("x1", cx) - .attr("y1", cy) - .attr("x2", tipX) - .attr("y2", tipY) - .attr("stroke", needleColor) - .attr("stroke-width", needleWidth) - .attr("stroke-linecap", "round"); - - // Center cap - needleGroup.append("circle") - .attr("cx", cx) - .attr("cy", cy) - .attr("r", capRadius) - .attr("fill", needleColor); - - // Optional: animation (we'll keep simple for now) - } - - // ----- Ticks ----- - if (ticksProps.show) { - const tickCount = ticksProps.count ?? 5; - const tickLength = ticksProps.length ?? 5; - const tickPosition = ticksProps.position ?? "outside"; - const tickAngles = d3.range(tickCount).map(i => { - const ratio = i / (tickCount - 1); - return startAngleRad + ratio * (endAngleRad - startAngleRad); + } else if (segments?.length) { + const scaleAngle = d3 + .scaleLinear() + .domain([min, max]) + .range([startA, endA]) + .clamp(true); + // Half the configured gap, converted from px to radians at this radius, + // so adjoining segments get visible separation like distinct blocks. + const gapRad = resolvedArc.gap / 2 / outerRadius || 0; + + const segArcGen = d3 + .arc<{ startAngle: number; endAngle: number; r: number }>() + .innerRadius((d) => d.r - thickness) + .outerRadius((d) => d.r) + .cornerRadius(resolvedArc.cornerRadius || thickness / 4) + .startAngle((d) => d.startAngle) + .endAngle((d) => d.endAngle); + + segments.forEach((seg, idx) => { + const segStart = scaleAngle(seg.from) + gapRad; + const segEnd = scaleAngle(seg.to) - gapRad; + if (segEnd <= segStart) return; + + const fill = resolveFill( + defs, + `anedya-gauge-segment-fill-${idx}`, + seg.color, + "currentColor" + ); + barGroup + .append("path") + .attr("class", resolveSlot("segment")) + .attr("fill", fill) + .attr("stroke", "none") + .attr( + "d", + segArcGen({ + startAngle: segStart, + endAngle: segEnd, + r: outerRadius, + })! + ); }); + } else { + const valueAngle = angleScale(clampedValue); + const barColorRaw: GaugeColor | undefined = + color ?? + (thresholds?.length + ? [...thresholds] + .sort((a, b) => a.value - b.value) + .reduce( + (acc, th) => (clampedValue >= th.value ? th.color : acc), + thresholds[0].color + ) + : undefined); + + const barFill = resolveFill( + defs, + "anedya-gauge-bar-fill", + barColorRaw, + "currentColor" + ); + + const path = barGroup + .append("path") + .attr("class", resolveSlot("bar")) + .attr("fill", barFill) + .attr("stroke", "none"); + + const from = fillMode === "solid" ? startA : startA; + const to = fillMode === "solid" ? endA : valueAngle; + + path + .datum({ + startAngle: startA, + endAngle: + prevValueRef.current != null + ? angleScale(prevValueRef.current) + : startA, + r: outerRadius, + }) + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("d", function (d: any) { + const i2 = d3.interpolate(d.endAngle, to); + return (t) => { + d.endAngle = i2(t); + return arcGen({ + startAngle: from, + endAngle: d.endAngle, + r: outerRadius, + })!; + }; + }); + } - tickAngles.forEach(angle => { - const cos = Math.cos(angle - Math.PI / 2); - const sin = Math.sin(angle - Math.PI / 2); - let innerP, outerP; - const baseR = (tickPosition === "inside") ? innerRadius : outerRadius; - if (tickPosition === "inside") { - innerP = { x: cx + (baseR - tickLength) * cos, y: cy + (baseR - tickLength) * sin }; - outerP = { x: cx + baseR * cos, y: cy + baseR * sin }; - } else if (tickPosition === "outside") { - innerP = { x: cx + baseR * cos, y: cy + baseR * sin }; - outerP = { x: cx + (baseR + tickLength) * cos, y: cy + (baseR + tickLength) * sin }; - } else { // cross - innerP = { x: cx + (baseR - tickLength / 2) * cos, y: cy + (baseR - tickLength / 2) * sin }; - outerP = { x: cx + (baseR + tickLength / 2) * cos, y: cy + (baseR + tickLength / 2) * sin }; - } - svg.append("line") - .attr("x1", innerP.x) - .attr("y1", innerP.y) - .attr("x2", outerP.x) - .attr("y2", outerP.y) + // --- Ticks --- + const tickGroup = root.select("g.anedya-gauge-ticks"); + tickGroup.selectAll("*").remove(); + if (resolvedTicks.show) { + const count = Math.max(2, resolvedTicks.count); + const tickR = + resolvedTicks.position === "inside" + ? outerRadius - thickness + : resolvedTicks.position === "cross" + ? outerRadius - thickness / 2 + : outerRadius + 4; + d3.range(count).forEach((i) => { + const t = i / (count - 1); + const tv = min + t * (max - min); + const a = angleScale(tv); + const x1 = Math.sin(a) * tickR; + const y1 = -Math.cos(a) * tickR; + const x2 = + Math.sin(a) * + (tickR + + (resolvedTicks.position === "inside" + ? -resolvedTicks.length + : resolvedTicks.length)); + const y2 = + -Math.cos(a) * + (tickR + + (resolvedTicks.position === "inside" + ? -resolvedTicks.length + : resolvedTicks.length)); + tickGroup + .append("line") .attr("class", resolveSlot("tick")) - .attr("stroke-width", 1); - }); - - if (ticksProps.labels) { - const labelOffset = (ticksProps.position === "outside" ? 15 : -15); - tickAngles.forEach((angle, i) => { - const val = min + (i / (tickCount - 1)) * (max - min); - const cos = Math.cos(angle - Math.PI / 2); - const sin = Math.sin(angle - Math.PI / 2); - const labelR = outerRadius + labelOffset; - const x = cx + labelR * cos; - const y = cy + labelR * sin; - svg.append("text") - .attr("x", x) - .attr("y", y) + .attr("stroke", "currentColor") + .attr("x1", x1) + .attr("y1", y1) + .attr("x2", x2) + .attr("y2", y2); + + if (resolvedTicks.labels) { + const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); + const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); + tickGroup + .append("text") + .attr("class", resolveSlot("tickLabel")) + .attr("x", lx) + .attr("y", ly) .attr("text-anchor", "middle") .attr("dominant-baseline", "middle") - .attr("class", resolveSlot("tickLabel")) - .text(Math.round(val).toString()); - }); - } + .text(String(Math.round(tv))); + } + }); } - // ----- Scale labels (min/max) ----- - if (scaleProps.minLabel || scaleProps.maxLabel) { - // Place labels at the start/end of the arc, outside - const minAngle = startAngleRad; - const maxAngle = endAngleRad; - const labelDist = outerRadius + 20; - const minX = cx + labelDist * Math.cos(minAngle - Math.PI / 2); - const minY = cy + labelDist * Math.sin(minAngle - Math.PI / 2); - const maxX = cx + labelDist * Math.cos(maxAngle - Math.PI / 2); - const maxY = cy + labelDist * Math.sin(maxAngle - Math.PI / 2); - - if (scaleProps.minLabel) { - svg.append("text") - .attr("x", minX) - .attr("y", minY) - .attr("text-anchor", "middle") - .attr("dominant-baseline", "middle") - .attr("class", resolveSlot("tickLabel")) - .text(scaleProps.minLabel); + // --- Needle --- + const needleGroup = root.select("g.anedya-gauge-needle"); + if (resolvedNeedle.show && variant !== "multiBar") { + const len = needlePixelLength(resolvedNeedle.length, outerRadius); + const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); + + needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); + const needleEl = needleGroup.insert( + shape.tag as any, + "circle.anedya-gauge-needle-cap" + ); + needleEl + .attr("class", resolveSlot("needle")) + .attr("fill", resolvedNeedle.color || "currentColor") + .attr("stroke", resolvedNeedle.color || "currentColor"); + Object.entries(shape.attrs).forEach(([k, v]) => + needleEl.attr( + k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), + v as any + ) + ); + + let cap = needleGroup.select( + "circle.anedya-gauge-needle-cap" + ); + if (cap.empty()) { + cap = needleGroup + .append("circle") + .attr( + "class", + twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) + ); } - if (scaleProps.maxLabel) { - svg.append("text") - .attr("x", maxX) - .attr("y", maxY) - .attr("text-anchor", "middle") - .attr("dominant-baseline", "middle") - .attr("class", resolveSlot("tickLabel")) - .text(scaleProps.maxLabel); + cap + .attr("r", resolvedNeedle.capRadius) + .attr("fill", resolvedNeedle.color || "currentColor"); + + const targetDeg = angleScale(clampedValue) / DEG2RAD; + if (resolvedNeedle.animation) { + needleGroup + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("transform", function () { + const current = needleGroup.attr("data-angle") + ? +needleGroup.attr("data-angle")! + : startA / DEG2RAD; + const interp = d3.interpolate(current, targetDeg); + return (t) => { + const a = interp(t); + needleGroup.attr("data-angle", String(a)); + return `rotate(${a})`; + }; + }); + } else { + needleGroup + .attr("transform", `rotate(${targetDeg})`) + .attr("data-angle", String(targetDeg)); } + needleGroup.attr("opacity", 1); + } else { + needleGroup.attr("opacity", 0); } + prevValueRef.current = clampedValue; }, [ - value, variant, min, max, effectiveWidth, effectiveHeight, - arcProps, trackProps, fillMode, bars, needleProps, segments, - thresholds, gradient, ticksProps, scaleProps, resolveSlot + boxWidth, + boxHeight, + cx, + cy, + outerRadius, + thickness, + variant, + clampedValue, + min, + max, + fillMode, + color, + JSON.stringify(bars), + JSON.stringify(segments), + JSON.stringify(thresholds), + resolvedTrack.show, + resolvedTrack.color, + resolvedNeedle.show, + resolvedNeedle.type, + resolvedNeedle.length, + resolvedNeedle.width, + resolvedNeedle.color, + resolvedNeedle.capRadius, + resolvedNeedle.animation, + resolvedTicks.show, + resolvedTicks.count, + resolvedTicks.position, + resolvedTicks.length, + resolvedTicks.labels, + resolvedAnimation.duration, + resolvedAnimation.easing, + resolveSlot, ]); - // ----- Center value text (HTML) ----- - const displayValue = useMemo(() => { - if (value == null) return "β€”"; - if (valueLabelProps.formatter) return valueLabelProps.formatter(value); - const prec = valueLabelProps.precision ?? 0; - const num = value.toFixed(prec); - return `${valueLabelProps.prefix ?? ""}${num}${valueLabelProps.suffix ?? ""}`; - }, [value, valueLabelProps]); - - // ----- Needle label (HTML) ----- - const needleLabelText = useMemo(() => { - if (!needleLabelProps.show || value == null) return null; - if (needleLabelProps.formatter) return needleLabelProps.formatter(value); - return `${value}`; - }, [value, needleLabelProps]); - - // ----- Render ----- + // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- + const handlePointerMove = useCallback( + (e: React.PointerEvent) => { + if (!resolvedTooltip.show && !onHover) return; + const rect = svgRef.current!.getBoundingClientRect(); + const x = e.clientX - rect.left - cx; + const y = e.clientY - rect.top - cy; + const dist = Math.hypot(x, y); + if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { + setHoverValue(null); + onHover?.(null); + return; + } + let a = Math.atan2(x, -y); + const hv = angleScale.invert(a); + const clamped = Math.min(max, Math.max(min, hv)); + setHoverValue(clamped); + onHover?.(clamped); + if (tooltipRef.current) { + tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; + tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; + } + }, + [ + cx, + cy, + outerRadius, + thickness, + angleScale, + min, + max, + onHover, + resolvedTooltip.show, + ] + ); + + const handlePointerLeave = useCallback(() => { + setHoverValue(null); + onHover?.(null); + }, [onHover]); + + const handleClick = useCallback( + () => onClick?.(clampedValue), + [onClick, clampedValue] + ); + + const formattedValue = resolvedValueLabel.formatter + ? resolvedValueLabel.formatter(clampedValue) + : `${resolvedValueLabel.prefix}${clampedValue.toFixed( + resolvedValueLabel.precision + )}${resolvedValueLabel.suffix}`; + + const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); + return (
onHover?.(true)} - onMouseLeave={() => onHover?.(false)} + onClick={handleClick} > {title && {title}} - {loading ? ( -
- -
- ) : error ? ( - {error} - ) : ( - <> - + + + - - {/* Center value (HTML overlay) */} - {valueLabelProps.show !== false && ( -
- - {displayValue} - - {needleLabelText && ( - - {needleLabelText} - + + + + - )} - + /> + + + + + {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( +
+ {scale?.minLabel} + {scale?.maxLabel} +
)} - {/* Tooltip placeholder */} - {tooltip?.show && ( -
- {/* D3 tooltip handling can be added later */} + {resolvedValueLabel.show && ( + {formattedValue} + )} + + {resolvedNeedleLabel.show && needleLabelText && ( + {needleLabelText} + )} + + {variable && {variable}} + + {resolvedTooltip.show && hoverValue != null && ( +
+ {hoverValue.toFixed(resolvedValueLabel.precision)}
)}
); -} \ No newline at end of file +} diff --git a/src/hooks/useResizeObserver.ts b/src/hooks/useResizeObserver.ts index be0198ec..45e007e9 100644 --- a/src/hooks/useResizeObserver.ts +++ b/src/hooks/useResizeObserver.ts @@ -1,36 +1,40 @@ -import { useRef, useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; -interface ElementSize { +export interface ObservedSize { width: number; height: number; } -export function useResizeObserver(): { - ref: React.RefObject; - width: number; - height: number; -} { - const containerRef = useRef(null); - const [size, setSize] = useState({ width: 0, height: 0 }); +/** + * Observes the border-box size of the returned ref's element and + * returns it. Used by every widget that needs to redraw its D3 + * geometry (arc radius, needle length, bar scales, etc.) when the + * container is resized β€” mobile, tablet, laptop, desktop, or a + * consumer-resized card, all handled the same way. + */ +export function useResizeObserver(enabled = true) { + const ref = useRef(null); + const [size, setSize] = useState({ width: 0, height: 0 }); useEffect(() => { - const node = containerRef.current; - if (!node) return; + if (!enabled || !ref.current) return; + const el = ref.current; - // Create the observer (non‑generic) - const observer = new ResizeObserver((entries) => { - if (!entries.length) return; - const { width, height } = entries[0].contentRect; + const ro = new ResizeObserver((entries) => { + const entry = entries[0]; + const box = entry.borderBoxSize?.[0]; + const width = box ? box.inlineSize : entry.contentRect.width; + const height = box ? box.blockSize : entry.contentRect.height; setSize({ width, height }); }); - observer.observe(node); + ro.observe(el); + // Seed immediately so first paint isn't 0x0 while waiting on the first callback. + const rect = el.getBoundingClientRect(); + setSize({ width: rect.width, height: rect.height }); - // Cleanup - return () => { - observer.disconnect(); - }; - }, []); // empty dependency β†’ runs once after mount + return () => ro.disconnect(); + }, [enabled]); - return { ref: containerRef, ...size }; + return { ref, size } as const; } \ No newline at end of file diff --git a/src/styles/base.css b/src/styles/base.css index 34769c57..67ade6b1 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -8,6 +8,7 @@ @source "../widgets/**/*.{ts,tsx}"; @source "../themes/**/*.{ts,tsx}"; @source "../common.ts"; +@source "../types/gauge.ts"; /* ---------- Widget defaults ---------- */ @@ -56,63 +57,33 @@ container-name: anedya-card; container-type: inline-size; container-name: anedya-gauge; - /* Sizing */ - --anedya-gauge-padding: 1rem; - --anedya-gauge-title-size: 0.875rem; - - /* Arc */ - --anedya-gauge-track-stroke: #e2e8f0; - --anedya-gauge-track-fill: transparent; - --anedya-gauge-bar-stroke: #3b82f6; - --anedya-gauge-bar-fill: transparent; - --anedya-gauge-thickness: 12; - - /* Needle */ - --anedya-gauge-needle-color: #334155; - --anedya-gauge-needle-cap-color: #334155; - - /* Center value */ - --anedya-gauge-center-value-size: 2rem; - --anedya-gauge-center-value-weight: 700; - --anedya-gauge-center-value-color: #1e293b; - - /* Needle label */ - --anedya-gauge-needle-label-size: 0.75rem; - --anedya-gauge-needle-label-color: #64748b; - - /* Ticks */ - --anedya-gauge-tick-stroke: #94a3b8; - --anedya-gauge-tick-label-size: 0.625rem; - --anedya-gauge-tick-label-color: #64748b; + --anedya-gauge-padding: 0.75rem; + --anedya-gauge-gap: 0.25rem; - /* Segments */ - --anedya-gauge-segment-stroke: #e2e8f0; - - --anedya-gauge-gap: 0.5rem; + --anedya-gauge-title-size: 0.875rem; + --anedya-gauge-value-size: 1.75rem; + --anedya-gauge-unit-size: 0.875rem; + --anedya-gauge-label-size: 0.75rem; + --anedya-gauge-tick-size: 0.625rem; } -/* Container queries scale typography (like Card) */ -@container anedya-gauge(min-width: 280px) { - .anedya-gauge { - --anedya-gauge-title-size: 0.9375rem; - --anedya-gauge-center-value-size: 2.25rem; - --anedya-gauge-needle-label-size: 0.8125rem; - --anedya-gauge-tick-label-size: 0.6875rem; - } -} -@container anedya-gauge(min-width: 400px) { +@container anedya-gauge (min-width: 260px) { .anedya-gauge { - --anedya-gauge-title-size: 1.0625rem; - --anedya-gauge-center-value-size: 2.75rem; - --anedya-gauge-needle-label-size: 0.875rem; - --anedya-gauge-tick-label-size: 0.75rem; + --anedya-gauge-padding: 1rem; + --anedya-gauge-value-size: 2.25rem; + --anedya-gauge-unit-size: 1rem; + --anedya-gauge-label-size: 0.875rem; + --anedya-gauge-tick-size: 0.75rem; } } -@container anedya-gauge(min-width: 560px) { + +@container anedya-gauge (min-width: 380px) { .anedya-gauge { - --anedya-gauge-title-size: 1.1875rem; - --anedya-gauge-center-value-size: 3.25rem; - --anedya-gauge-needle-label-size: 1rem; - --anedya-gauge-tick-label-size: 0.875rem; + --anedya-gauge-padding: 1.25rem; + --anedya-gauge-title-size: 1rem; + --anedya-gauge-value-size: 3rem; + --anedya-gauge-unit-size: 1.125rem; + --anedya-gauge-label-size: 1rem; + --anedya-gauge-tick-size: 0.8125rem; } } \ No newline at end of file diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index 2fb5c7ea..31b6138c 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -1,63 +1,67 @@ -import { SlotClassNames, WidgetTheme } from "../types/root"; - -// The exact same slot names we'll use in the widget -export type GaugeSlot = - | "container" - | "title" - | "track" - | "bar" - | "needle" - | "centerValue" - | "needleLabel" - | "tick" - | "tickLabel" - | "segment"; +import { GaugeSlot } from "../types/gauge"; +import { WidgetTheme } from "../types/root"; export const GAUGE_DEFAULT_CLASSES: Record = { container: - "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-gauge-padding)] gap-[var(--anedya-gauge-gap)]", - title: - "text-[length:var(--anedya-gauge-title-size)] font-medium", - track: - "[stroke:var(--anedya-gauge-track-stroke)] [fill:var(--anedya-gauge-track-fill)]", - bar: - "[stroke:var(--anedya-gauge-bar-stroke)] [fill:var(--anedya-gauge-bar-fill)]", - needle: - "[fill:var(--anedya-gauge-needle-color)] [stroke:var(--anedya-gauge-needle-color)]", - centerValue: - "text-[length:var(--anedya-gauge-center-value-size)] font-[var(--anedya-gauge-center-value-weight)] text-[var(--anedya-gauge-center-value-color)]", - needleLabel: - "text-[length:var(--anedya-gauge-needle-label-size)] text-[var(--anedya-gauge-needle-label-color)]", - tick: - "[stroke:var(--anedya-gauge-tick-stroke)]", + "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", + title: "text-[length:var(--anedya-gauge-title-size)] font-medium", + track: "", + bar: "", + segment: "", + needle: "", + needleCap: "", + tick: "", tickLabel: - "text-[length:var(--anedya-gauge-tick-label-size)] text-[var(--anedya-gauge-tick-label-color)] fill-[var(--anedya-gauge-tick-label-color)]", - segment: - "[stroke:var(--anedya-gauge-segment-stroke)]", + "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", + scaleLabel: + "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", + value: "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", + unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", + label: "text-[length:var(--anedya-gauge-label-size)]", + tooltip: + "pointer-events-none absolute z-10 rounded-md px-2 py-1 text-xs font-medium shadow-md", }; -export const lightTheme: WidgetTheme = { +export const gaugeLightTheme: WidgetTheme = { classNames: { - container: "bg-white border-slate-200", + container: "", title: "text-slate-500", - centerValue: "text-slate-900", - needleLabel: "text-slate-400", - tickLabel: "fill-slate-400 text-slate-400", + track: "text-slate-200", // read via `currentColor` on the track path + bar: "text-indigo-500", + segment: "", + needle: "text-slate-700", + needleCap: "text-slate-700", + tick: "text-slate-300", + tickLabel: "text-slate-400", + scaleLabel: "text-slate-400", + value: "text-slate-900", + unit: "text-slate-500", + label: "text-slate-400", + tooltip: "bg-slate-900 text-white", }, }; -export const darkTheme: WidgetTheme = { +export const gaugeDarkTheme: WidgetTheme = { classNames: { - container: "bg-slate-900 border-slate-800", + container: "", title: "text-slate-400", - centerValue: "text-white", - needleLabel: "text-slate-500", - tickLabel: "fill-slate-500 text-slate-500", + track: "text-slate-700", + bar: "text-indigo-400", + segment: "", + needle: "text-slate-200", + needleCap: "text-slate-200", + tick: "text-slate-600", + tickLabel: "text-slate-500", + scaleLabel: "text-slate-500", + value: "text-white", + unit: "text-slate-400", + label: "text-slate-500", + tooltip: "bg-slate-100 text-slate-900", }, }; export const gaugeThemes = { - light: lightTheme, - dark: darkTheme, + light: gaugeLightTheme, + dark: gaugeDarkTheme, } as const; -export type GaugeThemeName = keyof typeof gaugeThemes; \ No newline at end of file +export const DEFAULT_GAUGE_THEME = gaugeLightTheme; diff --git a/src/types/gauge.ts b/src/types/gauge.ts new file mode 100644 index 00000000..96bb9994 --- /dev/null +++ b/src/types/gauge.ts @@ -0,0 +1,113 @@ +import { CardSlot } from "./card"; // for BuiltInTheme reuse pattern + +export type GaugeVariant = "progress" | "needle" | "segmented" | "multiBar"; + +export type GaugeSlot = + | "container" + | "title" + | "track" + | "bar" + | "segment" + | "needle" + | "needleCap" + | "tick" + | "tickLabel" + | "scaleLabel" + | "value" + | "unit" + | "label" + | "tooltip"; + +export interface GaugeArcConfig { + /** Degrees, 0 = 12 o'clock, clockwise-positive. */ + startAngle?: number; + endAngle?: number; + radius?: number; + /** Bar/track thickness in px. Auto-computed from radius if omitted. */ + thickness?: number; + cornerRadius?: number; + /** Gap between concentric bars (multiBar) or track/bar (px). */ + gap?: number; +} + +export interface GaugeTrackConfig { + show?: boolean; + color?: string; +} + +export type GaugeColor = string | string[]; + +export interface GaugeBarSpec { + value: number; + color?: GaugeColor; + label?: string; +} + +export type NeedleType = "line" | "rounded" | "drop" | "triangle"; + +export interface GaugeNeedleConfig { + show?: boolean; + type?: NeedleType; + /** Preset or px. Relative to computed radius when a preset is used. */ + length?: "short" | "medium" | "full" | number; + width?: number; + color?: string; + capRadius?: number; + animation?: boolean; +} + +export interface GaugeLabelsConfig { + show?: boolean; + position?: "inside" | "outside"; +} + +export interface GaugeValueLabelConfig { + show?: boolean; + precision?: number; + prefix?: string; + suffix?: string; + formatter?: (value: number) => string; +} + +export interface GaugeNeedleLabelConfig { + show?: boolean; + formatter?: (value: number) => string; +} + +export interface GaugeScaleConfig { + minLabel?: string; + maxLabel?: string; +} + +export interface GaugeTicksConfig { + show?: boolean; + count?: number; + position?: "inside" | "outside" | "cross"; + length?: number; + labels?: boolean; +} + +export interface GaugeSegment { + from: number; + to: number; + color: GaugeColor; + } + + export interface GaugeThreshold { + value: number; + color: GaugeColor; + } + +export interface GaugeGradientConfig { + colors: string[]; +} + +export interface GaugeAnimationConfig { + duration?: number; + /** Any d3-ease export name, e.g. "easeCubicOut", "easeElasticOut". */ + easing?: string; +} + +export interface GaugeTooltipConfig { + show?: boolean; +} \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 25c2e06b..1ed16b40 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -2,6 +2,7 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; +import "../../../dist/style.css"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = @@ -132,8 +133,68 @@ export default function App() { }} /> - {/* */} - + {/*
*/} + {"Hello"}) + }} + labels={{ + show:true, + position:"outside" + }} + scale={{ + minLabel:"Minimum", + maxLabel:"Maximum" + }} + ticks={{ + show:true, + count:10, + position:"outside", + length:10, + labels:true, + }} + animation={{ + duration:5000, + easing:"easeElasticOut" + }} + tooltip={{ + show:false + }} + classNames={{ + title:"text-white", + tickLabel:"text-white text-lg", + label:"text-white", + value:"text-white" + }} + /> + {/*
*/} {/* Needle gauge with threshold colors */} {/*
*/} + +{/* ============================================================ + * 1. Progress variant (default) β€” track + fill + needle, + * value below needle, variable name below that. + * ============================================================ */} + {/*
+ +
*/} + + {/* ============================================================ + * 2. Needle variant β€” explicit ticks + needle, no fill sweep + * (needle-only reading, like a speedometer). + * ============================================================ */} + {/*
*/} + + {/*
*/} + + {/* ============================================================ + * 3. Segmented variant β€” colored ranges (risk zones), with + * needle enabled to point at the current value (like your + * ChartExpo reference image). + * ============================================================ */} + {/*
*/} + + {/*
*/} + + {/* ============================================================ + * 4. Multi-bar variant β€” concentric bars, each with its own + * value/color/label. Needle is not shown for this variant. + * ============================================================ */} + {/*
*/} + {/* */} + {/*
*/} + + {/* ============================================================ + * 5. Bonus β€” gradient fill on the progress variant, per your + * "user can pass their own gradient" requirement. + * ============================================================ */} + {/*
*/} + + {/*
*/} +
); } From 297623636ac345057285dc2fbec58945f027be49 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 11:06:04 +0530 Subject: [PATCH 33/66] commit --- src/styles/base.css | 31 ++--------------- test/my-app/src/App.jsx | 76 ++++++++++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/src/styles/base.css b/src/styles/base.css index d26ffe70..bf42cde9 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -22,33 +22,10 @@ transition: padding 0.25s ease, gap 0.25s ease; } -<<<<<<< HEAD - -@container anedya-card(min-width: 320px) { - .anedya-card { - --anedya-card-padding: 1.25rem; - - --anedya-card-title-size: 1rem; - --anedya-card-value-size: 2.75rem; - --anedya-card-unit-size: 1.125rem; - --anedya-card-label-size: 0.875rem; - - --anedya-card-gap: 0.75rem; - } +.anedya-card>* { + transition: font-size 0.25s ease; } -@container anedya-card(min-width: 420px) { - .anedya-card { - --anedya-card-padding: 1.5rem; - - --anedya-card-title-size: 1.125rem; - --anedya-card-value-size: 3.5rem; - --anedya-card-unit-size: 1.25rem; - --anedya-card-label-size: 1rem; - - --anedya-card-gap: 1rem; - } -} .anedya-gauge { container-type: inline-size; @@ -83,8 +60,4 @@ --anedya-gauge-label-size: 1rem; --anedya-gauge-tick-size: 0.8125rem; } -======= -.anedya-card > * { - transition: font-size 0.25s ease; ->>>>>>> cd33dfd8d79dc13659866a58763b62db17a1511e } \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index a58b956f..4a00e561 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -4,7 +4,8 @@ import { CardWidget } from "../../../src"; import "../../../dist/style.css"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; +const token = + "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; const anedya = new Anedya(); @@ -17,7 +18,7 @@ const node = anedya.newNode(client, nodeId); * app. Only specify the slots you actually want to change from the * built-in default β€” anything omitted falls back to lightTheme/darkTheme. */ -const emeraldTheme= { +const emeraldTheme = { classNames: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", @@ -30,21 +31,35 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
+
{/* ============================================================ * 1. Default appearance β€” no theme, no styles, no * formatting props. Every fallback in the widget in one place. * ============================================================ */} - + {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same * effect across every widget instance that uses it. * ============================================================ */} - + {/* Built-in preset names also work directly: */} - + {/* ============================================================ * 3. styles vs className β€” THE distinction to understand: @@ -75,7 +90,6 @@ export default function App() { value: "text-red-500 text-5xl", // <- targets the INNER "value" slot specifically title: "uppercase tracking-wider", // <- targets the INNER "title" slot specifically }} - /> {/* ============================================================ @@ -133,26 +147,24 @@ export default function App() { title="Threshold Coloring" unit="%" precision={1} - - onDataChange={(data) => { - if (!data) return; - - if (data.value > 80) { - return { - title: "High Humidity", - theme: "dark", - classNames: { - value: "text-red-500" - } - }; - } - - return { - title: "Humidity", - theme: "light" - }; - }} - + onDataChange={(data) => { + if (!data) return; + + if (data.value > 80) { + return { + title: "High Humidity", + theme: "dark", + classNames: { + value: "text-red-500", + }, + }; + } + + return { + title: "Humidity", + theme: "light", + }; + }} /> {/* ============================================================ @@ -160,7 +172,15 @@ export default function App() { * applied as inline styles on the container, independent of the * whole classNames/theme system. * ============================================================ */} - +
); } From d6c9571d148496e5ba914bc854db4efea46e040c Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 11:14:23 +0530 Subject: [PATCH 34/66] commit --- dist/index.d.mts | 192 ++++++++++++++-------------------- dist/index.d.ts | 123 ---------------------- dist/style.css | 2 - package-lock.json | 82 ++++----------- src/helpers/validate.ts | 5 +- src/themes/gaugeTheme.ts | 13 ++- test/my-app/package-lock.json | 94 +---------------- 7 files changed, 110 insertions(+), 401 deletions(-) delete mode 100644 dist/index.d.ts delete mode 100644 dist/style.css diff --git a/dist/index.d.mts b/dist/index.d.mts index 233e6e7c..77e68b7e 100644 --- a/dist/index.d.mts +++ b/dist/index.d.mts @@ -1,123 +1,83 @@ -import * as react from 'react'; - -type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; -type BuiltInTheme = "light" | "dark"; - -/** - * Generic per-slot class overrides. Every widget defines its own slot - * names (Card: container/title/value/unit/label, Chart: container/line/ - * axis/...) but they all share this same shape. - */ -type SlotClassNames = Partial>; -/** - * A widget theme is simply a reusable collection of Tailwind (or plain - * CSS) classes for a widget's slots. - * - * Themes are merged in three layers: - * - * built-in theme - * ↓ - * user theme - * ↓ - * widget classNames prop - * - * Later layers win via `twMerge`. - */ -interface WidgetTheme { - classNames: SlotClassNames; -} - -/** - * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this - * rather than repeating client/node/sizing/theme plumbing per widget. - * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. - */ -interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; -} - +import { a as LabelFormatPreset, n as FormatOptions, o as SlotClassNames, r as FormatPreset, t as AnedyaWidgetBaseProps } from "./common-DARTvNue.mjs"; +//#region src/components/CardWidget.d.ts type CardSlot = "container" | "title" | "value" | "unit" | "label"; /** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ interface CardData { - value: number; - timestamp: number; + value: number; + timestamp: number; } type CardWidgetUpdate = Partial>; interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - classNames?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * classNames: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; + unit?: string; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + decimalPlaces?: number; + /** + * Full custom formatting function β€” receives the raw fetched value, + * returns the exact string to display. + * + * Takes precedence over both `format` and `decimalPlaces`. + */ + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + styles?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * styles: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; + /** + * Named formatting preset for common unit types β€” auto-scales both + * the displayed number and its unit (e.g. `"bytes"` turns `500000` + * into `"500"` + `"KB"`). + * + * When set, this overrides the `unit` prop β€” the preset determines + * its own unit per value. + * + * Ignored if `formatValue` is also provided. + */ + format?: FormatPreset; + /** Options for the active `format` preset β€” e.g. `{ precision: 2, locale: "en-IN" }`. */ + formatOptions?: FormatOptions; + /** + * Named preset for the last-updated label's format. Ignored if + * `labelText` is also provided (which always takes precedence). + * Defaults to `"time"`, matching the widget's previous fixed behavior. + */ + labelFormat?: LabelFormatPreset; } -declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react.JSX.Element; - -export { CardWidget }; - +declare function CardWidget({ node, variable, title, unit, decimalPlaces, formatValue, labelText, styles, onDataChange, theme, className, width, height, minWidth, maxWidth, format, formatOptions, labelFormat }: CardWidgetProps): React.JSX.Element; +//#endregion +export { CardWidget }; \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts deleted file mode 100644 index 233e6e7c..00000000 --- a/dist/index.d.ts +++ /dev/null @@ -1,123 +0,0 @@ -import * as react from 'react'; - -type CardSlot$1 = "container" | "title" | "value" | "unit" | "label"; -type BuiltInTheme = "light" | "dark"; - -/** - * Generic per-slot class overrides. Every widget defines its own slot - * names (Card: container/title/value/unit/label, Chart: container/line/ - * axis/...) but they all share this same shape. - */ -type SlotClassNames = Partial>; -/** - * A widget theme is simply a reusable collection of Tailwind (or plain - * CSS) classes for a widget's slots. - * - * Themes are merged in three layers: - * - * built-in theme - * ↓ - * user theme - * ↓ - * widget classNames prop - * - * Later layers win via `twMerge`. - */ -interface WidgetTheme { - classNames: SlotClassNames; -} - -/** - * Every widget takes this shape as its base. Widget-specific props - * (e.g. Card's `unit`/`precision`, Chart's `tickCount`) extend this - * rather than repeating client/node/sizing/theme plumbing per widget. - * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. - */ -interface AnedyaWidgetBaseProps { - node: any; - variable: string; - /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ - from?: number; - to?: number; - limit?: number; - title?: string; - /** - * Optional theme for the widget. - * - * A theme is a reusable collection of classes for the widget's slots. - * It is merged with the widget's built-in defaults, while the - * `classNames` prop is applied afterwards for per-instance overrides. - */ - theme?: WidgetTheme | BuiltInTheme; - /** Applied to the widget's outermost element, on top of everything else. */ - className?: string; - width?: number; - height?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - aspectRatio?: number; -} - -type CardSlot = "container" | "title" | "value" | "unit" | "label"; -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -interface CardData { - value: number; - timestamp: number; -} -type CardWidgetUpdate = Partial>; -interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - precision?: number; - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - classNames?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * classNames: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; -} -declare function CardWidget({ node, variable, title, unit, precision, formatValue, labelText, classNames, onDataChange, theme, className, width, height, minWidth, maxWidth, }: CardWidgetProps): react.JSX.Element; - -export { CardWidget }; - diff --git a/dist/style.css b/dist/style.css deleted file mode 100644 index 56c45db0..00000000 --- a/dist/style.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-900:oklch(37.8% .077 168.94);--color-indigo-400:oklch(67.3% .182 276.935);--color-indigo-500:oklch(58.5% .233 277.117);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-bold:700;--tracking-wider:.05em;--radius-md:.375rem;--radius-xl:.75rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.z-10{z-index:10}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.-mt-2{margin-top:calc(var(--spacing) * -2)}.block{display:block}.contents{display:contents}.flex{display:flex}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-auto{height:auto}.w-full{width:100%}.shrink{flex-shrink:1}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.resize{resize:both}.flex-col{flex-direction:column}.items-center{align-items:center}.items-end{align-items:flex-end}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-\[var\(--anedya-card-gap\)\]{gap:var(--anedya-card-gap)}.gap-\[var\(--anedya-gauge-gap\)\]{gap:var(--anedya-gauge-gap)}.rounded{border-radius:.25rem}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-emerald-200{border-color:var(--color-emerald-200)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-800{border-color:var(--color-slate-800)}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-white{background-color:var(--color-white)}.fill-current{fill:currentColor}.p-\[var\(--anedya-card-padding\)\]{padding:var(--anedya-card-padding)}.p-\[var\(--anedya-gauge-padding\)\]{padding:var(--anedya-gauge-padding)}.px-2{padding-inline:calc(var(--spacing) * 2)}.py-1{padding-block:var(--spacing)}.text-center{text-align:center}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[length\:var\(--anedya-card-label-size\)\]{font-size:var(--anedya-card-label-size)}.text-\[length\:var\(--anedya-card-title-size\)\]{font-size:var(--anedya-card-title-size)}.text-\[length\:var\(--anedya-card-unit-size\)\]{font-size:var(--anedya-card-unit-size)}.text-\[length\:var\(--anedya-card-value-size\)\]{font-size:var(--anedya-card-value-size)}.text-\[length\:var\(--anedya-gauge-label-size\)\]{font-size:var(--anedya-gauge-label-size)}.text-\[length\:var\(--anedya-gauge-tick-size\)\]{font-size:var(--anedya-gauge-tick-size)}.text-\[length\:var\(--anedya-gauge-title-size\)\]{font-size:var(--anedya-gauge-title-size)}.text-\[length\:var\(--anedya-gauge-unit-size\)\]{font-size:var(--anedya-gauge-unit-size)}.text-\[length\:var\(--anedya-gauge-value-size\)\]{font-size:var(--anedya-gauge-value-size)}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-900{color:var(--color-emerald-900)}.text-indigo-400{color:var(--color-indigo-400)}.text-indigo-500{color:var(--color-indigo-500)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-700{color:var(--color-slate-700)}.text-slate-900{color:var(--color-slate-900)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (min-width:48rem){.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.md\:text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}}@media (min-width:80rem){.xl\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}}}.anedya-card{--anedya-card-padding:1rem;--anedya-card-title-size:.875rem;--anedya-card-value-size:2.25rem;--anedya-card-unit-size:1rem;--anedya-card-label-size:.75rem;--anedya-card-gap:.5rem;container:anedya-card/inline-size}@container anedya-card(min-width: 320px){.anedya-card{--anedya-card-padding:1.25rem;--anedya-card-title-size:1rem;--anedya-card-value-size:2.75rem;--anedya-card-unit-size:1.125rem;--anedya-card-label-size:.875rem;--anedya-card-gap:.75rem}}@container anedya-card(min-width: 420px){.anedya-card{--anedya-card-padding:1.5rem;--anedya-card-title-size:1.125rem;--anedya-card-value-size:3.5rem;--anedya-card-unit-size:1.25rem;--anedya-card-label-size:1rem;--anedya-card-gap:1rem}}.anedya-gauge{--anedya-gauge-padding:.75rem;--anedya-gauge-gap:.25rem;--anedya-gauge-title-size:.875rem;--anedya-gauge-value-size:1.75rem;--anedya-gauge-unit-size:.875rem;--anedya-gauge-label-size:.75rem;--anedya-gauge-tick-size:.625rem;container:anedya-gauge/inline-size}@container anedya-gauge (min-width:260px){.anedya-gauge{--anedya-gauge-padding:1rem;--anedya-gauge-value-size:2.25rem;--anedya-gauge-unit-size:1rem;--anedya-gauge-label-size:.875rem;--anedya-gauge-tick-size:.75rem}}@container anedya-gauge (min-width:380px){.anedya-gauge{--anedya-gauge-padding:1.25rem;--anedya-gauge-title-size:1rem;--anedya-gauge-value-size:3rem;--anedya-gauge-unit-size:1.125rem;--anedya-gauge-label-size:1rem;--anedya-gauge-tick-size:.8125rem}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false} diff --git a/package-lock.json b/package-lock.json index fd16b92c..e1887761 100644 --- a/package-lock.json +++ b/package-lock.json @@ -191,29 +191,6 @@ "win32" ] }, - "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -1484,16 +1461,15 @@ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "dev": true, "license": "MIT", - "optional": true, "peer": true, "dependencies": { "csstype": "^3.2.2" } }, - "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -2816,6 +2792,19 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -2880,13 +2869,14 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", + "peer": true, "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -2963,6 +2953,7 @@ "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@oxc-project/types": "=0.140.0", "@rolldown/pluginutils": "^1.0.0" @@ -3120,20 +3111,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3230,19 +3207,6 @@ } } }, - "node_modules/tsdown/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", diff --git a/src/helpers/validate.ts b/src/helpers/validate.ts index c1e14133..46ecdff1 100644 --- a/src/helpers/validate.ts +++ b/src/helpers/validate.ts @@ -11,8 +11,5 @@ export function validateRequiredProps( ", " )}`; - - - console.error(message); - + console.error(message); } diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index 31b6138c..fc3b315c 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -4,7 +4,8 @@ import { WidgetTheme } from "../types/root"; export const GAUGE_DEFAULT_CLASSES: Record = { container: "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", - title: "text-[length:var(--anedya-gauge-title-size)] font-medium", + title: + "text-[length:var(--anedya-gauge-title-size)] font-medium", track: "", bar: "", segment: "", @@ -15,7 +16,8 @@ export const GAUGE_DEFAULT_CLASSES: Record = { "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", scaleLabel: "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", - value: "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", + value: + "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", label: "text-[length:var(--anedya-gauge-label-size)]", tooltip: @@ -60,8 +62,5 @@ export const gaugeDarkTheme: WidgetTheme = { }, }; -export const gaugeThemes = { - light: gaugeLightTheme, - dark: gaugeDarkTheme, -} as const; -export const DEFAULT_GAUGE_THEME = gaugeLightTheme; +export const gaugeThemes = { light: gaugeLightTheme, dark: gaugeDarkTheme } as const; +export const DEFAULT_GAUGE_THEME = gaugeLightTheme; \ No newline at end of file diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index f7c5d615..1e4becda 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -30,37 +30,7 @@ "vite": "^8.0.1" } }, - "../..": { - "name": "public-widget-sdk", - "version": "5.5.0", - "license": "ISC", - "dependencies": { - "@anedyasystems/anedya-frontend-sdk": "^0.1.1", - "@types/d3": "^7.4.3", - "clsx": "^2.1.1", - "d3": "^7.9.0", - "tailwind-merge": "^3.6.0" - }, - "devDependencies": { - "@base-ui/react": "^1.6.0", - "@tailwindcss/cli": "^4.3.3", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tailwindcss": "^4.3.2", - "tsdown": "^0.22.13", - "typescript": "^5.7.3" - }, - "peerDependencies": { - "@base-ui/react": "^1.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "../../../../anedya-widgets-react": { - "extraneous": true - }, + "../..": {}, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -301,31 +271,6 @@ "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -401,6 +346,7 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -444,6 +390,7 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -990,7 +937,6 @@ "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/Boshen" } @@ -1018,7 +964,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1036,7 +981,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1054,7 +998,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1072,7 +1015,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1090,7 +1032,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1108,7 +1049,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1126,7 +1066,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1144,7 +1083,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1162,7 +1100,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1180,7 +1117,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1198,7 +1134,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1216,7 +1151,6 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1231,7 +1165,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", @@ -1254,7 +1187,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1272,7 +1204,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -2973,6 +2904,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3684,24 +3616,6 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", From 9408bc03158a7e67e04485ee8fbf4fab8e2a647c Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 11:22:47 +0530 Subject: [PATCH 35/66] correct ts.config.json --- test/my-app/src/App.jsx | 64 +++++++++++++++++++++++++++++++++++++++++ ts.config.json | 1 - 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 4a00e561..6ac6356c 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -1,6 +1,7 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; +import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; import "../../../dist/style.css"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; @@ -181,6 +182,69 @@ export default function App() { maxWidth={400} height={200} /> + + { + "Hello"; + }, + }} + labels={{ + show: true, + position: "outside", + }} + scale={{ + minLabel: "Minimum", + maxLabel: "Maximum", + }} + ticks={{ + show: true, + count: 10, + position: "outside", + length: 10, + labels: true, + }} + animation={{ + duration: 5000, + easing: "easeElasticOut", + }} + tooltip={{ + show: false, + }} + classNames={{ + title: "text-white", + tickLabel: "text-white text-lg", + label: "text-white", + value: "text-white", + }} + />
); } diff --git a/ts.config.json b/ts.config.json index df059977..78d862e1 100644 --- a/ts.config.json +++ b/ts.config.json @@ -12,7 +12,6 @@ "forceConsistentCasingInFileNames": true, "declaration": true, "noEmit": true, - "types":["react", "react-dom"], "isolatedDeclarations": true }, "include": ["src"] From 67b2087e3a8405eef6c3f171df1641f20742092c Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 14:19:32 +0530 Subject: [PATCH 36/66] add gauge widget --- .../GaugeChart/GaugeChartWidget.tsx | 1478 ++++++++++++----- src/themes/gaugeTheme.ts | 99 +- src/types/gauge.ts | 173 +- test/my-app/src/App.jsx | 472 +++--- 4 files changed, 1500 insertions(+), 722 deletions(-) diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index 63e74e65..bb233012 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -1,3 +1,935 @@ +// import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +// import * as d3 from "d3"; +// import { twMerge } from "tailwind-merge"; +// import { AnedyaWidgetBaseProps } from "../../common"; +// import { SlotClassNames, WidgetTheme } from "../../types/root"; +// import { +// GaugeAnimationConfig, +// GaugeArcConfig, +// GaugeBarSpec, +// GaugeColor, +// GaugeLabelsConfig, +// GaugeNeedleConfig, +// GaugeNeedleLabelConfig, +// GaugeScaleConfig, +// GaugeSegment, +// GaugeSlot, +// GaugeThreshold, +// GaugeTicksConfig, +// GaugeTooltipConfig, +// GaugeTrackConfig, +// GaugeValueLabelConfig, +// GaugeVariant, +// } from "../../types/gauge"; +// import { +// DEFAULT_GAUGE_THEME, +// GAUGE_DEFAULT_CLASSES, +// gaugeDarkTheme, +// gaugeLightTheme, +// } from "../../themes/gaugeTheme"; +// import { useResizeObserver } from "../../hooks/useResizeObserver"; + +// export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { +// variant?: GaugeVariant; +// /** Used before live data arrives, or standalone in dummy-data mode. */ +// value?: number; +// min?: number; +// max?: number; +// size?: number; +// responsive?: boolean; + +// arc?: GaugeArcConfig; +// track?: GaugeTrackConfig; +// fillMode?: "progress" | "solid"; +// /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ +// color?: GaugeColor; +// bars?: GaugeBarSpec[]; + +// needle?: GaugeNeedleConfig; +// labels?: GaugeLabelsConfig; +// valueLabel?: GaugeValueLabelConfig; +// needleLabel?: GaugeNeedleLabelConfig; +// scale?: GaugeScaleConfig; +// ticks?: GaugeTicksConfig; +// segments?: GaugeSegment[]; +// thresholds?: GaugeThreshold[]; +// animation?: GaugeAnimationConfig; +// tooltip?: GaugeTooltipConfig; + +// classNames?: SlotClassNames; +// style?: React.CSSProperties; + +// onClick?: (value: number) => void; +// onHover?: (value: number | null) => void; +// onValueChange?: (value: number) => void; +// } + +// const DEG2RAD = Math.PI / 180; + +// const DEFAULT_ARC: Required> = { +// startAngle: -90, +// endAngle: 90, +// cornerRadius: 0, +// gap: 6, +// }; + +// const DEFAULT_ANIMATION: Required = { +// duration: 750, +// easing: "easeCubicOut", +// }; + +// function resolveEase(name: string) { +// return (d3 as any)[name] ?? d3.easeCubicOut; +// } + +// function needlePixelLength( +// length: GaugeNeedleConfig["length"], +// radius: number +// ) { +// if (typeof length === "number") return length; +// switch (length) { +// case "short": +// return radius * 0.55; +// case "full": +// return radius * 0.95; +// case "medium": +// default: +// return radius * 0.75; +// } +// } + +// /** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ +// function needleShape( +// type: NonNullable, +// length: number, +// width: number +// ) { +// const w = width; +// switch (type) { +// case "line": +// return { +// tag: "line", +// attrs: { +// x1: 0, +// y1: 0, +// x2: 0, +// y2: -length, +// strokeWidth: w, +// strokeLinecap: "butt", +// }, +// }; +// case "rounded": +// return { +// tag: "line", +// attrs: { +// x1: 0, +// y1: 0, +// x2: 0, +// y2: -length, +// strokeWidth: w, +// strokeLinecap: "round", +// }, +// }; +// case "triangle": { +// const half = w / 2; +// return { +// tag: "polygon", +// attrs: { +// points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ +// -length * 0.15 +// }`, +// }, +// }; +// } +// case "drop": +// default: { +// const half = w / 2; +// // Teardrop: rounded base, sharp tip. +// const d = `M ${-half} 0 +// C ${-half} ${-length * 0.35}, ${-w} ${ +// -length * 0.7 +// }, 0 ${-length} +// C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 +// A ${half} ${half} 0 1 1 ${-half} 0 Z`; +// return { tag: "path", attrs: { d } }; +// } +// } +// } + +// function isGradientColor(c?: GaugeColor): c is string[] { +// return Array.isArray(c) && c.length >= 2; +// } + +// /** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ +// function resolveFill( +// defs: d3.Selection, +// id: string, +// color: GaugeColor | undefined, +// fallback: string +// ): string { +// if (!color) return fallback; +// if (!isGradientColor(color)) return color; + +// let grad = defs.select(`#${id}`); +// if (grad.empty()) { +// grad = defs.append("linearGradient").attr("id", id); +// } +// grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); +// grad.selectAll("stop").remove(); +// color.forEach((c, i) => +// grad +// .append("stop") +// .attr("offset", `${(i / (color.length - 1)) * 100}%`) +// .attr("stop-color", c) +// ); +// return `url(#${id})`; +// } + +// /** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ +// function getArcBounds(startDeg: number, endDeg: number) { +// const lo = Math.min(startDeg, endDeg); +// const hi = Math.max(startDeg, endDeg); +// const angles = [startDeg, endDeg]; +// for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); + +// let minX = Infinity, +// maxX = -Infinity, +// minY = Infinity, +// maxY = -Infinity; +// angles.forEach((deg) => { +// const a = deg * DEG2RAD; +// const x = Math.sin(a); +// const y = -Math.cos(a); +// minX = Math.min(minX, x); +// maxX = Math.max(maxX, x); +// minY = Math.min(minY, y); +// maxY = Math.max(maxY, y); +// }); +// return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; +// } + +// export function GaugeWidget({ +// node, +// variable, +// title, +// theme, +// className, +// style, +// width, +// height, +// minWidth = 160, +// maxWidth = 480, +// minHeight = 160, +// maxHeight = 480, +// aspectRatio, + +// variant = "progress", +// value: valueProp, +// min = 0, +// max = 100, +// size, +// responsive = true, + +// arc, +// track, +// fillMode = "progress", +// color, +// bars, + +// needle, +// labels, +// valueLabel, +// needleLabel, +// scale, +// ticks, +// segments, +// thresholds, +// animation, +// tooltip, + +// classNames = {}, +// onClick, +// onHover, +// onValueChange, +// }: GaugeWidgetProps) { +// const svgRef = useRef(null); +// const tooltipRef = useRef(null); +// const prevValueRef = useRef(min); + +// const [fetchedValue, setFetchedValue] = useState(null); +// const [hoverValue, setHoverValue] = useState(null); + +// // ---- Live data fetch (mirrors CardWidget) ---- +// useEffect(() => { +// if (!node) return; +// let mounted = true; + +// node +// .getLatestData(variable) +// .then((res: any) => { +// if (!mounted) return; +// if (res?.isSuccess && res?.isDataAvailable) { +// setFetchedValue(res.data.value); +// } +// }) +// .catch(() => { +// /* fall back to `value` prop / dummy data silently */ +// }); + +// return () => { +// mounted = false; +// }; +// }, [node, variable]); + +// const rawValue = fetchedValue ?? valueProp ?? min; +// const clampedValue = Math.min(max, Math.max(min, rawValue)); + +// useEffect(() => { +// onValueChange?.(clampedValue); +// }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps + +// // ---- Responsive sizing ---- +// const { ref: wrapperRef, size: dims } = useResizeObserver( +// responsive && size == null +// ); + +// // ---- Resolved config (defaults per variant) ---- +// const resolvedArc = { ...DEFAULT_ARC, ...arc }; + +// const resolvedTrack: Required = { +// show: track?.show ?? true, +// color: track?.color ?? "", +// }; + +// const needleShownByDefault = variant === "progress" || variant === "needle"; + +// const resolvedNeedle: Required> & { +// length: NonNullable; +// } = { +// show: needle?.show ?? needleShownByDefault, +// type: needle?.type ?? "rounded", +// length: needle?.length ?? "medium", +// width: needle?.width ?? 4, +// color: needle?.color ?? "", +// capRadius: needle?.capRadius ?? 6, +// animation: needle?.animation ?? true, +// }; + +// const resolvedLabels: Required = { +// show: labels?.show ?? true, +// position: labels?.position ?? "outside", +// }; + +// const resolvedValueLabel: Required< +// Omit +// > & { formatter?: (v: number) => string } = { +// show: valueLabel?.show ?? true, +// precision: valueLabel?.precision ?? 0, +// prefix: valueLabel?.prefix ?? "", +// suffix: valueLabel?.suffix ?? "", +// formatter: valueLabel?.formatter, +// }; + +// const resolvedNeedleLabel: Required< +// Omit +// > & { formatter?: (v: number) => string } = { +// show: needleLabel?.show ?? false, +// formatter: needleLabel?.formatter, +// }; + +// const resolvedTicks: Required = { +// show: ticks?.show ?? (variant === "needle" || variant === "segmented"), +// count: ticks?.count ?? 5, +// position: ticks?.position ?? "outside", +// length: ticks?.length ?? 6, +// labels: ticks?.labels ?? true, +// }; + +// const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; + +// const resolvedTooltip: Required = { +// show: tooltip?.show ?? true, +// }; + +// // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- +// const resolvedTheme: WidgetTheme = +// theme === "dark" +// ? gaugeDarkTheme +// : theme === "light" +// ? gaugeLightTheme +// : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; + +// const resolveSlot = useCallback( +// (slot: GaugeSlot) => +// twMerge( +// GAUGE_DEFAULT_CLASSES[slot], +// resolvedTheme.styles[slot], +// classNames[slot] +// ), +// [resolvedTheme, classNames] +// ); + +// const boxWidth = size ?? width ?? (dims.width || 240); + +// const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); + +// const bounds = useMemo( +// () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), +// [resolvedArc.startAngle, resolvedArc.endAngle] +// ); + +// const pad = 8; +// // Reserve room below the arc for value/needle-label/variable text so +// // the dome never gets crowded β€” bigger reserve when the value label is on. +// const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + +// // Ticks (and their number labels) draw *outside* the arc's own radius, +// // so the radius-fit math below must shrink the arc enough to leave +// // room for them β€” otherwise tick labels get clipped by the SVG +// // viewBox, which looked like "some ticks are hidden". +// const tickOverflow = +// resolvedTicks.show && resolvedTicks.position !== "inside" +// ? resolvedTicks.length + (resolvedTicks.labels ? 26 : 8) +// : 0; +// // Scale min/max labels also draw past the arc's radius at the two ends. +// const scaleLabelOverflow = +// resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) ? 24 : 0; +// const edgeOverflow = Math.max(tickOverflow, scaleLabelOverflow); + +// const availW = boxWidth - pad * 2 - edgeOverflow * 2; +// const availH = boxHeight * (1 - textReserve) - pad * 2 - edgeOverflow; + +// const outerRadius = +// resolvedArc.radius ?? +// Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); + +// const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); + +// // Center the arc's bounding box within the available width, anchor its top at `pad`. +// const cx = +// pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; +// const cy = pad - bounds.minY * outerRadius; + +// const angleScale = useMemo( +// () => +// d3 +// .scaleLinear() +// .domain([min, max]) +// .range([ +// resolvedArc.startAngle * DEG2RAD, +// resolvedArc.endAngle * DEG2RAD, +// ]) +// .clamp(true), +// [min, max, resolvedArc.startAngle, resolvedArc.endAngle] +// ); + +// // ---- D3 draw ---- +// useEffect(() => { +// if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; + +// const svg = d3.select(svgRef.current); +// const defs = svg.select("defs"); +// const root = svg.select("g.anedya-gauge-root"); +// root.attr("transform", `translate(${cx},${cy})`); + +// const ease = resolveEase(resolvedAnimation.easing); +// const arcGen = d3 +// .arc<{ startAngle: number; endAngle: number; r: number }>() +// .innerRadius((d) => d.r - thickness) +// .outerRadius((d) => d.r) +// .cornerRadius(resolvedArc.cornerRadius) +// .startAngle((d) => d.startAngle) +// .endAngle((d) => d.endAngle); + +// const startA = resolvedArc.startAngle * DEG2RAD; +// const endA = resolvedArc.endAngle * DEG2RAD; + +// // --- Track --- +// const trackSel = root.select( +// "path.anedya-gauge-track-path" +// ); +// if (resolvedTrack.show && variant !== "multiBar") { +// trackSel +// .attr( +// "d", +// arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! +// ) +// .attr("fill", resolvedTrack.color || "currentColor") +// .attr("opacity", 1); +// } else { +// trackSel.attr("opacity", 0); +// } + +// // --- Bar (progress / solid / segmented base) --- +// const barGroup = root.select("g.anedya-gauge-bar-group"); +// barGroup.selectAll("*").remove(); + +// if (variant === "multiBar" && bars?.length) { +// const maxBars = bars.slice(0, 10); +// maxBars.forEach((bar, i) => { +// const r = outerRadius - i * (thickness + resolvedArc.gap); +// if (resolvedTrack.show) { +// barGroup +// .append("path") +// .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) +// .attr( +// "class", +// twMerge("anedya-gauge-multibar-track", resolveSlot("track")) +// ) +// .attr("fill", resolvedTrack.color || "currentColor") +// .attr("stroke", "none"); +// } +// const valAngle = d3 +// .scaleLinear() +// .domain([min, max]) +// .range([startA, endA]) +// .clamp(true)(bar.value); + +// const barFill = resolveFill( +// defs, +// `anedya-gauge-bar-fill-${i}`, +// bar.color, +// "currentColor" +// ); + +// const path = barGroup +// .append("path") +// .attr("class", resolveSlot("bar")) +// .attr("fill", barFill) +// .attr("stroke", "none"); +// path +// .datum({ startAngle: startA, endAngle: startA, r }) +// .attr("d", arcGen as any) +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("d", function (d: any) { +// const i2 = d3.interpolate(d.endAngle, valAngle); +// return (t) => { +// d.endAngle = i2(t); +// return arcGen(d)!; +// }; +// }); +// }); +// } else if (segments?.length) { +// const scaleAngle = d3 +// .scaleLinear() +// .domain([min, max]) +// .range([startA, endA]) +// .clamp(true); +// // Half the configured gap, converted from px to radians at this radius, +// // so adjoining segments get visible separation like distinct blocks. +// const gapRad = resolvedArc.gap / 2 / outerRadius || 0; + +// const segArcGen = d3 +// .arc<{ startAngle: number; endAngle: number; r: number }>() +// .innerRadius((d) => d.r - thickness) +// .outerRadius((d) => d.r) +// .cornerRadius(resolvedArc.cornerRadius || thickness / 4) +// .startAngle((d) => d.startAngle) +// .endAngle((d) => d.endAngle); + +// segments.forEach((seg, idx) => { +// const segStart = scaleAngle(seg.from) + gapRad; +// const segEnd = scaleAngle(seg.to) - gapRad; +// if (segEnd <= segStart) return; + +// const fill = resolveFill( +// defs, +// `anedya-gauge-segment-fill-${idx}`, +// seg.color, +// "currentColor" +// ); +// barGroup +// .append("path") +// .attr("class", resolveSlot("segment")) +// .attr("fill", fill) +// .attr("stroke", "none") +// .attr( +// "d", +// segArcGen({ +// startAngle: segStart, +// endAngle: segEnd, +// r: outerRadius, +// })! +// ); +// }); +// } else { +// const valueAngle = angleScale(clampedValue); +// const barColorRaw: GaugeColor | undefined = +// color ?? +// (thresholds?.length +// ? [...thresholds] +// .sort((a, b) => a.value - b.value) +// .reduce( +// (acc, th) => (clampedValue >= th.value ? th.color : acc), +// thresholds[0].color +// ) +// : undefined); + +// const barFill = resolveFill( +// defs, +// "anedya-gauge-bar-fill", +// barColorRaw, +// "currentColor" +// ); + +// const path = barGroup +// .append("path") +// .attr("class", resolveSlot("bar")) +// .attr("fill", barFill) +// .attr("stroke", "none"); + +// const from = fillMode === "solid" ? startA : startA; +// const to = fillMode === "solid" ? endA : valueAngle; + +// path +// .datum({ +// startAngle: startA, +// endAngle: +// prevValueRef.current != null +// ? angleScale(prevValueRef.current) +// : startA, +// r: outerRadius, +// }) +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("d", function (d: any) { +// const i2 = d3.interpolate(d.endAngle, to); +// return (t) => { +// d.endAngle = i2(t); +// return arcGen({ +// startAngle: from, +// endAngle: d.endAngle, +// r: outerRadius, +// })!; +// }; +// }); +// } + +// // --- Ticks --- +// const tickGroup = root.select("g.anedya-gauge-ticks"); +// tickGroup.selectAll("*").remove(); +// if (resolvedTicks.show) { +// const count = Math.max(2, resolvedTicks.count); +// const tickR = +// resolvedTicks.position === "inside" +// ? outerRadius - thickness +// : resolvedTicks.position === "cross" +// ? outerRadius - thickness / 2 +// : outerRadius + 4; +// d3.range(count).forEach((i) => { +// const t = i / (count - 1); +// const tv = min + t * (max - min); +// const a = angleScale(tv); +// const x1 = Math.sin(a) * tickR; +// const y1 = -Math.cos(a) * tickR; +// const x2 = +// Math.sin(a) * +// (tickR + +// (resolvedTicks.position === "inside" +// ? -resolvedTicks.length +// : resolvedTicks.length)); +// const y2 = +// -Math.cos(a) * +// (tickR + +// (resolvedTicks.position === "inside" +// ? -resolvedTicks.length +// : resolvedTicks.length)); +// tickGroup +// .append("line") +// .attr("class", resolveSlot("tick")) +// .attr("stroke", "currentColor") +// .attr("x1", x1) +// .attr("y1", y1) +// .attr("x2", x2) +// .attr("y2", y2); + +// if (resolvedTicks.labels) { +// const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); +// const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); +// tickGroup +// .append("text") +// .attr("class", resolveSlot("tickLabel")) +// .attr("x", lx) +// .attr("y", ly) +// .attr("text-anchor", "middle") +// .attr("dominant-baseline", "middle") +// .text(String(Math.round(tv))); +// } +// }); +// } +// // --- Scale min/max labels (drawn at the arc's real start/end points, +// // not floated at the container's edges) --- +// const scaleLabelGroup = root.select( +// "g.anedya-gauge-scale-labels" +// ); +// scaleLabelGroup.selectAll("*").remove(); +// if (resolvedLabels.show && (scale?.minLabel || scale?.maxLabel)) { +// const labelR = +// outerRadius + +// (resolvedTicks.show ? resolvedTicks.length + 16 : 12); + +// const drawScaleLabel = (angle: number, text: string) => { +// const x = Math.sin(angle) * labelR; +// const y = -Math.cos(angle) * labelR; +// // Anchor away from the point so the label doesn't overlap the arc: +// // labels on the left side end at x, labels on the right start at x. +// const anchor = x < -2 ? "end" : x > 2 ? "start" : "middle"; +// scaleLabelGroup +// .append("text") +// .attr("class", resolveSlot("scaleLabel")) +// .attr("x", x) +// .attr("y", y) +// .attr("text-anchor", anchor) +// .attr("dominant-baseline", "middle") +// .text(text); +// }; + +// if (scale?.minLabel) drawScaleLabel(startA, scale.minLabel); +// if (scale?.maxLabel) drawScaleLabel(endA, scale.maxLabel); +// } + +// // --- Needle --- +// const needleGroup = root.select("g.anedya-gauge-needle"); +// if (resolvedNeedle.show && variant !== "multiBar") { +// const len = needlePixelLength(resolvedNeedle.length, outerRadius); +// const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); + +// needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); +// const needleEl = needleGroup.insert( +// shape.tag as any, +// "circle.anedya-gauge-needle-cap" +// ); +// needleEl +// .attr("class", resolveSlot("needle")) +// .attr("fill", resolvedNeedle.color || "currentColor") +// .attr("stroke", resolvedNeedle.color || "currentColor"); +// Object.entries(shape.attrs).forEach(([k, v]) => +// needleEl.attr( +// k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), +// v as any +// ) +// ); + +// let cap = needleGroup.select( +// "circle.anedya-gauge-needle-cap" +// ); +// if (cap.empty()) { +// cap = needleGroup +// .append("circle") +// .attr( +// "class", +// twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) +// ); +// } +// cap +// .attr("r", resolvedNeedle.capRadius) +// .attr("fill", resolvedNeedle.color || "currentColor"); + +// const targetDeg = angleScale(clampedValue) / DEG2RAD; +// if (resolvedNeedle.animation) { +// needleGroup +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("transform", function () { +// const current = needleGroup.attr("data-angle") +// ? +needleGroup.attr("data-angle")! +// : startA / DEG2RAD; +// const interp = d3.interpolate(current, targetDeg); +// return (t) => { +// const a = interp(t); +// needleGroup.attr("data-angle", String(a)); +// return `rotate(${a})`; +// }; +// }); +// } else { +// needleGroup +// .attr("transform", `rotate(${targetDeg})`) +// .attr("data-angle", String(targetDeg)); +// } +// needleGroup.attr("opacity", 1); +// } else { +// needleGroup.attr("opacity", 0); +// } + +// prevValueRef.current = clampedValue; +// }, [ +// boxWidth, +// boxHeight, +// cx, +// cy, +// outerRadius, +// thickness, +// variant, +// clampedValue, +// min, +// max, +// fillMode, +// color, +// JSON.stringify(bars), +// JSON.stringify(segments), +// JSON.stringify(thresholds), +// resolvedTrack.show, +// resolvedTrack.color, +// resolvedNeedle.show, +// resolvedNeedle.type, +// resolvedNeedle.length, +// resolvedNeedle.width, +// resolvedNeedle.color, +// resolvedNeedle.capRadius, +// resolvedNeedle.animation, +// resolvedTicks.show, +// resolvedTicks.count, +// resolvedTicks.position, +// resolvedTicks.length, +// resolvedTicks.labels, +// resolvedAnimation.duration, +// resolvedAnimation.easing, +// resolveSlot, +// resolvedLabels.show, +// scale?.minLabel, +// scale?.maxLabel, +// ]); + +// // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- +// const handlePointerMove = useCallback( +// (e: React.PointerEvent) => { +// if (!resolvedTooltip.show && !onHover) return; +// const rect = svgRef.current!.getBoundingClientRect(); +// const x = e.clientX - rect.left - cx; +// const y = e.clientY - rect.top - cy; +// const dist = Math.hypot(x, y); +// if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { +// setHoverValue(null); +// onHover?.(null); +// return; +// } +// let a = Math.atan2(x, -y); +// const hv = angleScale.invert(a); +// const clamped = Math.min(max, Math.max(min, hv)); +// setHoverValue(clamped); +// onHover?.(clamped); +// if (tooltipRef.current) { +// tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; +// tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; +// } +// }, +// [ +// cx, +// cy, +// outerRadius, +// thickness, +// angleScale, +// min, +// max, +// onHover, +// resolvedTooltip.show, +// ] +// ); + +// const handlePointerLeave = useCallback(() => { +// setHoverValue(null); +// onHover?.(null); +// }, [onHover]); + +// const handleClick = useCallback( +// () => onClick?.(clampedValue), +// [onClick, clampedValue] +// ); + +// const formattedValue = resolvedValueLabel.formatter +// ? resolvedValueLabel.formatter(clampedValue) +// : `${resolvedValueLabel.prefix}${clampedValue.toFixed( +// resolvedValueLabel.precision +// )}${resolvedValueLabel.suffix}`; + +// const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); + +// return ( +//
+// {title && {title}} + +// +// +// +// +// +// +// +// +// +// +// +// + +// {/* {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( +//
+// {scale?.minLabel} +// {scale?.maxLabel} +//
+// )} */} + +// {resolvedValueLabel.show && ( +// {formattedValue} +// )} + +// {resolvedNeedleLabel.show && needleLabelText && ( +// {needleLabelText} +// )} + +// {variable && {variable}} + +// {resolvedTooltip.show && hoverValue != null && ( +//
+// {hoverValue.toFixed(resolvedValueLabel.precision)} +//
+// )} +//
+// ); +// } + + + import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import * as d3 from "d3"; import { twMerge } from "tailwind-merge"; @@ -6,20 +938,11 @@ import { SlotClassNames, WidgetTheme } from "../../types/root"; import { GaugeAnimationConfig, GaugeArcConfig, - GaugeBarSpec, GaugeColor, - GaugeLabelsConfig, GaugeNeedleConfig, - GaugeNeedleLabelConfig, - GaugeScaleConfig, - GaugeSegment, GaugeSlot, - GaugeThreshold, - GaugeTicksConfig, - GaugeTooltipConfig, GaugeTrackConfig, GaugeValueLabelConfig, - GaugeVariant, } from "../../types/gauge"; import { DEFAULT_GAUGE_THEME, @@ -30,7 +953,6 @@ import { import { useResizeObserver } from "../../hooks/useResizeObserver"; export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { - variant?: GaugeVariant; /** Used before live data arrives, or standalone in dummy-data mode. */ value?: number; min?: number; @@ -40,27 +962,17 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { arc?: GaugeArcConfig; track?: GaugeTrackConfig; - fillMode?: "progress" | "solid"; - /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ + /** Bar fill color. Pass an array of 2+ colors for a gradient. */ color?: GaugeColor; - bars?: GaugeBarSpec[]; needle?: GaugeNeedleConfig; - labels?: GaugeLabelsConfig; valueLabel?: GaugeValueLabelConfig; - needleLabel?: GaugeNeedleLabelConfig; - scale?: GaugeScaleConfig; - ticks?: GaugeTicksConfig; - segments?: GaugeSegment[]; - thresholds?: GaugeThreshold[]; animation?: GaugeAnimationConfig; - tooltip?: GaugeTooltipConfig; classNames?: SlotClassNames; style?: React.CSSProperties; onClick?: (value: number) => void; - onHover?: (value: number | null) => void; onValueChange?: (value: number) => void; } @@ -70,7 +982,6 @@ const DEFAULT_ARC: Required> = { startAngle: -90, endAngle: 90, cornerRadius: 0, - gap: 6, }; const DEFAULT_ANIMATION: Required = { @@ -78,14 +989,16 @@ const DEFAULT_ANIMATION: Required = { easing: "easeCubicOut", }; +// A dome (semicircle-ish) gauge only uses the top half of its box, so its +// natural height:width ratio is well under 1. This is the fallback used +// when no explicit height/aspectRatio is given. +const DEFAULT_HEIGHT_RATIO = 0.68; + function resolveEase(name: string) { return (d3 as any)[name] ?? d3.easeCubicOut; } -function needlePixelLength( - length: GaugeNeedleConfig["length"], - radius: number -) { +function needlePixelLength(length: GaugeNeedleConfig["length"], radius: number) { if (typeof length === "number") return length; switch (length) { case "short": @@ -98,57 +1011,32 @@ function needlePixelLength( } } -/** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ -function needleShape( - type: NonNullable, - length: number, - width: number -) { +/** Builds a needle shape pointing "up" (-y) from the origin; rotated into place via a group transform. */ +function needleShape(type: NonNullable, length: number, width: number) { const w = width; switch (type) { case "line": return { tag: "line", - attrs: { - x1: 0, - y1: 0, - x2: 0, - y2: -length, - strokeWidth: w, - strokeLinecap: "butt", - }, + attrs: { x1: 0, y1: 0, x2: 0, y2: -length, strokeWidth: w, strokeLinecap: "butt" }, }; case "rounded": return { tag: "line", - attrs: { - x1: 0, - y1: 0, - x2: 0, - y2: -length, - strokeWidth: w, - strokeLinecap: "round", - }, + attrs: { x1: 0, y1: 0, x2: 0, y2: -length, strokeWidth: w, strokeLinecap: "round" }, }; case "triangle": { const half = w / 2; return { tag: "polygon", - attrs: { - points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ - -length * 0.15 - }`, - }, + attrs: { points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${-length * 0.15}` }, }; } case "drop": default: { const half = w / 2; - // Teardrop: rounded base, sharp tip. - const d = `M ${-half} 0 - C ${-half} ${-length * 0.35}, ${-w} ${ - -length * 0.7 - }, 0 ${-length} + const d = `M ${-half} 0 + C ${-half} ${-length * 0.35}, ${-w} ${-length * 0.7}, 0 ${-length} C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 A ${half} ${half} 0 1 1 ${-half} 0 Z`; return { tag: "path", attrs: { d } }; @@ -160,7 +1048,7 @@ function isGradientColor(c?: GaugeColor): c is string[] { return Array.isArray(c) && c.length >= 2; } -/** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ +/** Ensures a with the given id/colors exists in and returns its url() reference. */ function resolveFill( defs: d3.Selection, id: string, @@ -185,17 +1073,14 @@ function resolveFill( return `url(#${id})`; } -/** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ +/** Normalized (r=1) bounding box of an arc sweep β€” handles semicircle, 270Β°, full circle, custom. */ function getArcBounds(startDeg: number, endDeg: number) { const lo = Math.min(startDeg, endDeg); const hi = Math.max(startDeg, endDeg); const angles = [startDeg, endDeg]; for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); - let minX = Infinity, - maxX = -Infinity, - minY = Infinity, - maxY = -Infinity; + let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; angles.forEach((deg) => { const a = deg * DEG2RAD; const x = Math.sin(a); @@ -219,11 +1104,10 @@ export function GaugeWidget({ height, minWidth = 160, maxWidth = 480, - minHeight = 160, - maxHeight = 480, + minHeight = 140, + maxHeight = 420, aspectRatio, - variant = "progress", value: valueProp, min = 0, max = 100, @@ -232,32 +1116,20 @@ export function GaugeWidget({ arc, track, - fillMode = "progress", color, - bars, needle, - labels, valueLabel, - needleLabel, - scale, - ticks, - segments, - thresholds, animation, - tooltip, classNames = {}, onClick, - onHover, onValueChange, }: GaugeWidgetProps) { const svgRef = useRef(null); - const tooltipRef = useRef(null); const prevValueRef = useRef(min); const [fetchedValue, setFetchedValue] = useState(null); - const [hoverValue, setHoverValue] = useState(null); // ---- Live data fetch (mirrors CardWidget) ---- useEffect(() => { @@ -289,21 +1161,23 @@ export function GaugeWidget({ }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps // ---- Responsive sizing ---- + // Disabled once `size` is set, since that fixes both dimensions explicitly. const { ref: wrapperRef, size: dims } = useResizeObserver( responsive && size == null ); - // ---- Resolved config (defaults per variant) ---- + // ---- Resolved config ---- const resolvedArc = { ...DEFAULT_ARC, ...arc }; + const resolvedTrack: Required = { show: track?.show ?? true, color: track?.color ?? "", }; - const needleShownByDefault = variant === "progress" || variant === "needle"; + const resolvedNeedle: Required> & { length: NonNullable; } = { - show: needle?.show ?? needleShownByDefault, + show: needle?.show ?? true, type: needle?.type ?? "rounded", length: needle?.length ?? "medium", width: needle?.width ?? 4, @@ -311,13 +1185,10 @@ export function GaugeWidget({ capRadius: needle?.capRadius ?? 6, animation: needle?.animation ?? true, }; - const resolvedLabels: Required = { - show: labels?.show ?? true, - position: labels?.position ?? "outside", - }; - const resolvedValueLabel: Required< - Omit - > & { formatter?: (v: number) => string } = { + + const resolvedValueLabel: Required> & { + formatter?: (v: number) => string; + } = { show: valueLabel?.show ?? true, precision: valueLabel?.precision ?? 0, prefix: valueLabel?.prefix ?? "", @@ -325,23 +1196,7 @@ export function GaugeWidget({ formatter: valueLabel?.formatter, }; - const resolvedNeedleLabel: Required< - Omit - > & { formatter?: (v: number) => string } = { - show: needleLabel?.show ?? false, - formatter: needleLabel?.formatter, - }; - const resolvedTicks: Required = { - show: ticks?.show ?? (variant === "needle" || variant === "segmented"), - count: ticks?.count ?? 5, - position: ticks?.position ?? "outside", - length: ticks?.length ?? 6, - labels: ticks?.labels ?? true, - }; const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; - const resolvedTooltip: Required = { - show: tooltip?.show ?? true, - }; // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- const resolvedTheme: WidgetTheme = @@ -353,16 +1208,15 @@ export function GaugeWidget({ const resolveSlot = useCallback( (slot: GaugeSlot) => - twMerge( - GAUGE_DEFAULT_CLASSES[slot], - resolvedTheme.classNames[slot], - classNames[slot] - ), + twMerge(GAUGE_DEFAULT_CLASSES[slot], resolvedTheme.styles[slot], classNames[slot]), [resolvedTheme, classNames] ); + // ---- Geometry ---- + // `size` fixes both dimensions in real CSS px so the wrapper's rendered + // box exactly matches the SVG viewBox (boxWidth === boxHeight === size). const boxWidth = size ?? width ?? (dims.width || 240); - const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); + const boxHeight = size ?? height ?? (dims.height || boxWidth * DEFAULT_HEIGHT_RATIO); const bounds = useMemo( () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), @@ -370,21 +1224,27 @@ export function GaugeWidget({ ); const pad = 8; - // Reserve room below the arc for value/needle-label/variable text so - // the dome never gets crowded β€” bigger reserve when the value label is on. + // Reserve room below the arc for the value + label text so the dome + // never gets crowded. const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; const availW = boxWidth - pad * 2; const availH = boxHeight * (1 - textReserve) - pad * 2; - const outerRadius = - resolvedArc.radius ?? - Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); + const maxFitRadius = Math.max( + 24, + Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1)) + ); + + // An explicit `arc.radius` is honored, but clamped so the arc can never + // overflow the container and get clipped by the SVG viewBox. + const outerRadius = resolvedArc.radius + ? Math.min(resolvedArc.radius, maxFitRadius) + : maxFitRadius; const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); // Center the arc's bounding box within the available width, anchor its top at `pad`. - const cx = - pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; + const cx = pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; const cy = pad - bounds.minY * outerRadius; const angleScale = useMemo( @@ -392,10 +1252,7 @@ export function GaugeWidget({ d3 .scaleLinear() .domain([min, max]) - .range([ - resolvedArc.startAngle * DEG2RAD, - resolvedArc.endAngle * DEG2RAD, - ]) + .range([resolvedArc.startAngle * DEG2RAD, resolvedArc.endAngle * DEG2RAD]) .clamp(true), [min, max, resolvedArc.startAngle, resolvedArc.endAngle] ); @@ -410,11 +1267,15 @@ export function GaugeWidget({ root.attr("transform", `translate(${cx},${cy})`); const ease = resolveEase(resolvedAnimation.easing); + // A cornerRadius larger than half the bar's thickness produces + // self-intersecting, glitchy arcs β€” clamp it to a safe maximum. + const safeCornerRadius = Math.min(resolvedArc.cornerRadius, thickness / 2); + const arcGen = d3 .arc<{ startAngle: number; endAngle: number; r: number }>() .innerRadius((d) => d.r - thickness) .outerRadius((d) => d.r) - .cornerRadius(resolvedArc.cornerRadius) + .cornerRadius(safeCornerRadius) .startAngle((d) => d.startAngle) .endAngle((d) => d.endAngle); @@ -422,260 +1283,72 @@ export function GaugeWidget({ const endA = resolvedArc.endAngle * DEG2RAD; // --- Track --- - const trackSel = root.select( - "path.anedya-gauge-track-path" - ); - if (resolvedTrack.show && variant !== "multiBar") { + const trackSel = root.select("path.anedya-gauge-track-path"); + if (resolvedTrack.show) { trackSel - .attr( - "d", - arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! - ) + .attr("d", arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })!) .attr("fill", resolvedTrack.color || "currentColor") .attr("opacity", 1); } else { trackSel.attr("opacity", 0); } - // --- Bar (progress / solid / segmented base) --- + // --- Bar (animated fill toward the current value) --- const barGroup = root.select("g.anedya-gauge-bar-group"); barGroup.selectAll("*").remove(); - if (variant === "multiBar" && bars?.length) { - const maxBars = bars.slice(0, 10); - maxBars.forEach((bar, i) => { - const r = outerRadius - i * (thickness + resolvedArc.gap); - if (resolvedTrack.show) { - barGroup - .append("path") - .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) - .attr( - "class", - twMerge("anedya-gauge-multibar-track", resolveSlot("track")) - ) - .attr("fill", resolvedTrack.color || "currentColor") - .attr("stroke", "none"); - } - const valAngle = d3 - .scaleLinear() - .domain([min, max]) - .range([startA, endA]) - .clamp(true)(bar.value); - - const barFill = resolveFill( - defs, - `anedya-gauge-bar-fill-${i}`, - bar.color, - "currentColor" - ); - - const path = barGroup - .append("path") - .attr("class", resolveSlot("bar")) - .attr("fill", barFill) - .attr("stroke", "none"); - path - .datum({ startAngle: startA, endAngle: startA, r }) - .attr("d", arcGen as any) - .transition() - .duration(resolvedAnimation.duration) - .ease(ease) - .attrTween("d", function (d: any) { - const i2 = d3.interpolate(d.endAngle, valAngle); - return (t) => { - d.endAngle = i2(t); - return arcGen(d)!; - }; - }); - }); - } else if (segments?.length) { - const scaleAngle = d3 - .scaleLinear() - .domain([min, max]) - .range([startA, endA]) - .clamp(true); - // Half the configured gap, converted from px to radians at this radius, - // so adjoining segments get visible separation like distinct blocks. - const gapRad = resolvedArc.gap / 2 / outerRadius || 0; - - const segArcGen = d3 - .arc<{ startAngle: number; endAngle: number; r: number }>() - .innerRadius((d) => d.r - thickness) - .outerRadius((d) => d.r) - .cornerRadius(resolvedArc.cornerRadius || thickness / 4) - .startAngle((d) => d.startAngle) - .endAngle((d) => d.endAngle); - - segments.forEach((seg, idx) => { - const segStart = scaleAngle(seg.from) + gapRad; - const segEnd = scaleAngle(seg.to) - gapRad; - if (segEnd <= segStart) return; - - const fill = resolveFill( - defs, - `anedya-gauge-segment-fill-${idx}`, - seg.color, - "currentColor" - ); - barGroup - .append("path") - .attr("class", resolveSlot("segment")) - .attr("fill", fill) - .attr("stroke", "none") - .attr( - "d", - segArcGen({ - startAngle: segStart, - endAngle: segEnd, - r: outerRadius, - })! - ); - }); - } else { - const valueAngle = angleScale(clampedValue); - const barColorRaw: GaugeColor | undefined = - color ?? - (thresholds?.length - ? [...thresholds] - .sort((a, b) => a.value - b.value) - .reduce( - (acc, th) => (clampedValue >= th.value ? th.color : acc), - thresholds[0].color - ) - : undefined); - - const barFill = resolveFill( - defs, - "anedya-gauge-bar-fill", - barColorRaw, - "currentColor" - ); - - const path = barGroup - .append("path") - .attr("class", resolveSlot("bar")) - .attr("fill", barFill) - .attr("stroke", "none"); - - const from = fillMode === "solid" ? startA : startA; - const to = fillMode === "solid" ? endA : valueAngle; - - path - .datum({ - startAngle: startA, - endAngle: - prevValueRef.current != null - ? angleScale(prevValueRef.current) - : startA, - r: outerRadius, - }) - .transition() - .duration(resolvedAnimation.duration) - .ease(ease) - .attrTween("d", function (d: any) { - const i2 = d3.interpolate(d.endAngle, to); - return (t) => { - d.endAngle = i2(t); - return arcGen({ - startAngle: from, - endAngle: d.endAngle, - r: outerRadius, - })!; - }; - }); - } - - // --- Ticks --- - const tickGroup = root.select("g.anedya-gauge-ticks"); - tickGroup.selectAll("*").remove(); - if (resolvedTicks.show) { - const count = Math.max(2, resolvedTicks.count); - const tickR = - resolvedTicks.position === "inside" - ? outerRadius - thickness - : resolvedTicks.position === "cross" - ? outerRadius - thickness / 2 - : outerRadius + 4; - d3.range(count).forEach((i) => { - const t = i / (count - 1); - const tv = min + t * (max - min); - const a = angleScale(tv); - const x1 = Math.sin(a) * tickR; - const y1 = -Math.cos(a) * tickR; - const x2 = - Math.sin(a) * - (tickR + - (resolvedTicks.position === "inside" - ? -resolvedTicks.length - : resolvedTicks.length)); - const y2 = - -Math.cos(a) * - (tickR + - (resolvedTicks.position === "inside" - ? -resolvedTicks.length - : resolvedTicks.length)); - tickGroup - .append("line") - .attr("class", resolveSlot("tick")) - .attr("stroke", "currentColor") - .attr("x1", x1) - .attr("y1", y1) - .attr("x2", x2) - .attr("y2", y2); - - if (resolvedTicks.labels) { - const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); - const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); - tickGroup - .append("text") - .attr("class", resolveSlot("tickLabel")) - .attr("x", lx) - .attr("y", ly) - .attr("text-anchor", "middle") - .attr("dominant-baseline", "middle") - .text(String(Math.round(tv))); - } + const valueAngle = angleScale(clampedValue); + const barFill = resolveFill(defs, "anedya-gauge-bar-fill", color, "currentColor"); + + const path = barGroup + .append("path") + .attr("class", resolveSlot("bar")) + .attr("fill", barFill) + .attr("stroke", "none"); + + path + .datum({ + startAngle: startA, + endAngle: + prevValueRef.current != null ? angleScale(prevValueRef.current) : startA, + r: outerRadius, + }) + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("d", function (d: any) { + const interp = d3.interpolate(d.endAngle, valueAngle); + return (t) => { + d.endAngle = interp(t); + return arcGen({ startAngle: startA, endAngle: d.endAngle, r: outerRadius })!; + }; }); - } // --- Needle --- const needleGroup = root.select("g.anedya-gauge-needle"); - if (resolvedNeedle.show && variant !== "multiBar") { + if (resolvedNeedle.show) { const len = needlePixelLength(resolvedNeedle.length, outerRadius); const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); - const needleEl = needleGroup.insert( - shape.tag as any, - "circle.anedya-gauge-needle-cap" - ); + const needleEl = needleGroup.insert(shape.tag as any, "circle.anedya-gauge-needle-cap"); needleEl .attr("class", resolveSlot("needle")) .attr("fill", resolvedNeedle.color || "currentColor") .attr("stroke", resolvedNeedle.color || "currentColor"); Object.entries(shape.attrs).forEach(([k, v]) => - needleEl.attr( - k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), - v as any - ) + needleEl.attr(k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), v as any) ); - let cap = needleGroup.select( - "circle.anedya-gauge-needle-cap" - ); + let cap = needleGroup.select("circle.anedya-gauge-needle-cap"); if (cap.empty()) { cap = needleGroup .append("circle") - .attr( - "class", - twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) - ); + .attr("class", twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap"))); } - cap - .attr("r", resolvedNeedle.capRadius) - .attr("fill", resolvedNeedle.color || "currentColor"); + cap.attr("r", resolvedNeedle.capRadius).attr("fill", resolvedNeedle.color || "currentColor"); - const targetDeg = angleScale(clampedValue) / DEG2RAD; + const targetDeg = valueAngle / DEG2RAD; if (resolvedNeedle.animation) { needleGroup .transition() @@ -693,9 +1366,7 @@ export function GaugeWidget({ }; }); } else { - needleGroup - .attr("transform", `rotate(${targetDeg})`) - .attr("data-angle", String(targetDeg)); + needleGroup.attr("transform", `rotate(${targetDeg})`).attr("data-angle", String(targetDeg)); } needleGroup.attr("opacity", 1); } else { @@ -710,15 +1381,11 @@ export function GaugeWidget({ cy, outerRadius, thickness, - variant, clampedValue, min, max, - fillMode, color, - JSON.stringify(bars), - JSON.stringify(segments), - JSON.stringify(thresholds), + resolvedArc.cornerRadius, resolvedTrack.show, resolvedTrack.color, resolvedNeedle.show, @@ -728,86 +1395,29 @@ export function GaugeWidget({ resolvedNeedle.color, resolvedNeedle.capRadius, resolvedNeedle.animation, - resolvedTicks.show, - resolvedTicks.count, - resolvedTicks.position, - resolvedTicks.length, - resolvedTicks.labels, resolvedAnimation.duration, resolvedAnimation.easing, resolveSlot, ]); - // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- - const handlePointerMove = useCallback( - (e: React.PointerEvent) => { - if (!resolvedTooltip.show && !onHover) return; - const rect = svgRef.current!.getBoundingClientRect(); - const x = e.clientX - rect.left - cx; - const y = e.clientY - rect.top - cy; - const dist = Math.hypot(x, y); - if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { - setHoverValue(null); - onHover?.(null); - return; - } - let a = Math.atan2(x, -y); - const hv = angleScale.invert(a); - const clamped = Math.min(max, Math.max(min, hv)); - setHoverValue(clamped); - onHover?.(clamped); - if (tooltipRef.current) { - tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; - tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; - } - }, - [ - cx, - cy, - outerRadius, - thickness, - angleScale, - min, - max, - onHover, - resolvedTooltip.show, - ] - ); - - const handlePointerLeave = useCallback(() => { - setHoverValue(null); - onHover?.(null); - }, [onHover]); - - const handleClick = useCallback( - () => onClick?.(clampedValue), - [onClick, clampedValue] - ); + const handleClick = useCallback(() => onClick?.(clampedValue), [onClick, clampedValue]); const formattedValue = resolvedValueLabel.formatter ? resolvedValueLabel.formatter(clampedValue) - : `${resolvedValueLabel.prefix}${clampedValue.toFixed( - resolvedValueLabel.precision - )}${resolvedValueLabel.suffix}`; - - const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); + : `${resolvedValueLabel.prefix}${clampedValue.toFixed(resolvedValueLabel.precision)}${resolvedValueLabel.suffix}`; return (
@@ -830,43 +1438,19 @@ export function GaugeWidget({ stroke="none" /> - - {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( -
- {scale?.minLabel} - {scale?.maxLabel} -
- )} - {resolvedValueLabel.show && ( {formattedValue} )} - {resolvedNeedleLabel.show && needleLabelText && ( - {needleLabelText} - )} - {variable && {variable}} - - {resolvedTooltip.show && hoverValue != null && ( -
- {hoverValue.toFixed(resolvedValueLabel.precision)} -
- )}
); -} +} \ No newline at end of file diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index fc3b315c..efffe9dd 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -1,64 +1,109 @@ +// import { GaugeSlot } from "../types/gauge"; +// import { WidgetTheme } from "../types/root"; + +// export const GAUGE_DEFAULT_CLASSES: Record = { +// container: +// "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", +// title: +// "text-[length:var(--anedya-gauge-title-size)] font-medium", +// track: "", +// bar: "", +// segment: "", +// needle: "", +// needleCap: "", +// tick: "", +// tickLabel: +// "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", +// scaleLabel: +// "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", +// value: +// "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", +// unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", +// label: "text-[length:var(--anedya-gauge-label-size)]", +// tooltip: +// "pointer-events-none absolute z-10 rounded-md px-2 py-1 text-xs font-medium shadow-md", +// }; + +// export const gaugeLightTheme: WidgetTheme = { +// styles: { +// container: "", +// title: "text-slate-500", +// track: "text-slate-200", // read via `currentColor` on the track path +// bar: "text-indigo-500", +// segment: "", +// needle: "text-slate-700", +// needleCap: "text-slate-700", +// tick: "text-slate-300", +// tickLabel: "text-slate-400", +// scaleLabel: "text-slate-400", +// value: "text-slate-900", +// unit: "text-slate-500", +// label: "text-slate-400", +// tooltip: "bg-slate-900 text-white", +// }, +// }; + +// export const gaugeDarkTheme: WidgetTheme = { +// styles: { +// container: "", +// title: "text-slate-400", +// track: "text-slate-700", +// bar: "text-indigo-400", +// segment: "", +// needle: "text-slate-200", +// needleCap: "text-slate-200", +// tick: "text-slate-600", +// tickLabel: "text-slate-500", +// scaleLabel: "text-slate-500", +// value: "text-white", +// unit: "text-slate-400", +// label: "text-slate-500", +// tooltip: "bg-slate-100 text-slate-900", +// }, +// }; + +// export const gaugeThemes = { light: gaugeLightTheme, dark: gaugeDarkTheme } as const; +// export const DEFAULT_GAUGE_THEME = gaugeLightTheme; + + import { GaugeSlot } from "../types/gauge"; import { WidgetTheme } from "../types/root"; export const GAUGE_DEFAULT_CLASSES: Record = { container: "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", - title: - "text-[length:var(--anedya-gauge-title-size)] font-medium", + title: "text-[length:var(--anedya-gauge-title-size)] font-medium", track: "", bar: "", - segment: "", needle: "", needleCap: "", - tick: "", - tickLabel: - "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", - scaleLabel: - "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", - value: - "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", - unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", + value: "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", label: "text-[length:var(--anedya-gauge-label-size)]", - tooltip: - "pointer-events-none absolute z-10 rounded-md px-2 py-1 text-xs font-medium shadow-md", }; export const gaugeLightTheme: WidgetTheme = { - classNames: { + styles: { container: "", title: "text-slate-500", track: "text-slate-200", // read via `currentColor` on the track path bar: "text-indigo-500", - segment: "", needle: "text-slate-700", needleCap: "text-slate-700", - tick: "text-slate-300", - tickLabel: "text-slate-400", - scaleLabel: "text-slate-400", value: "text-slate-900", - unit: "text-slate-500", label: "text-slate-400", - tooltip: "bg-slate-900 text-white", }, }; export const gaugeDarkTheme: WidgetTheme = { - classNames: { + styles: { container: "", title: "text-slate-400", track: "text-slate-700", bar: "text-indigo-400", - segment: "", needle: "text-slate-200", needleCap: "text-slate-200", - tick: "text-slate-600", - tickLabel: "text-slate-500", - scaleLabel: "text-slate-500", value: "text-white", - unit: "text-slate-400", label: "text-slate-500", - tooltip: "bg-slate-100 text-slate-900", }, }; diff --git a/src/types/gauge.ts b/src/types/gauge.ts index 96bb9994..c5ee4a4a 100644 --- a/src/types/gauge.ts +++ b/src/types/gauge.ts @@ -1,22 +1,126 @@ -import { CardSlot } from "./card"; // for BuiltInTheme reuse pattern +// import { CardSlot } from "./card"; // for BuiltInTheme reuse pattern + +// export type GaugeVariant = "progress" | "needle" | "segmented" | "multiBar"; + +// export type GaugeSlot = +// | "container" +// | "title" +// | "track" +// | "bar" +// | "segment" +// | "needle" +// | "needleCap" +// | "tick" +// | "tickLabel" +// | "scaleLabel" +// | "value" +// | "unit" +// | "label" +// | "tooltip"; + +// export interface GaugeArcConfig { +// /** Degrees, 0 = 12 o'clock, clockwise-positive. */ +// startAngle?: number; +// endAngle?: number; +// radius?: number; +// /** Bar/track thickness in px. Auto-computed from radius if omitted. */ +// thickness?: number; +// cornerRadius?: number; +// /** Gap between concentric bars (multiBar) or track/bar (px). */ +// gap?: number; +// } + +// export interface GaugeTrackConfig { +// show?: boolean; +// color?: string; +// } + +// export type GaugeColor = string | string[]; + +// export interface GaugeBarSpec { +// value: number; +// color?: GaugeColor; +// label?: string; +// } + +// export type NeedleType = "line" | "rounded" | "drop" | "triangle"; + +// export interface GaugeNeedleConfig { +// show?: boolean; +// type?: NeedleType; +// /** Preset or px. Relative to computed radius when a preset is used. */ +// length?: "short" | "medium" | "full" | number; +// width?: number; +// color?: string; +// capRadius?: number; +// animation?: boolean; +// } + +// export interface GaugeLabelsConfig { +// show?: boolean; +// position?: "inside" | "outside"; +// } + +// export interface GaugeValueLabelConfig { +// show?: boolean; +// precision?: number; +// prefix?: string; +// suffix?: string; +// formatter?: (value: number) => string; +// } + +// export interface GaugeNeedleLabelConfig { +// show?: boolean; +// formatter?: (value: number) => string; +// } + +// export interface GaugeScaleConfig { +// minLabel?: string; +// maxLabel?: string; +// } + +// export interface GaugeTicksConfig { +// show?: boolean; +// count?: number; +// position?: "inside" | "outside" | "cross"; +// length?: number; +// labels?: boolean; +// } + +// export interface GaugeSegment { +// from: number; +// to: number; +// color: GaugeColor; +// } + +// export interface GaugeThreshold { +// value: number; +// color: GaugeColor; +// } + +// export interface GaugeGradientConfig { +// colors: string[]; +// } + +// export interface GaugeAnimationConfig { +// duration?: number; +// /* .g. "easeCubicOut", "easeElasticOut". */ +// easing?: string; +// } -export type GaugeVariant = "progress" | "needle" | "segmented" | "multiBar"; +// export interface GaugeTooltipConfig { +// show?: boolean; +// } export type GaugeSlot = | "container" | "title" | "track" | "bar" - | "segment" | "needle" | "needleCap" - | "tick" - | "tickLabel" - | "scaleLabel" | "value" - | "unit" - | "label" - | "tooltip"; + | "label"; export interface GaugeArcConfig { /** Degrees, 0 = 12 o'clock, clockwise-positive. */ @@ -26,8 +130,6 @@ export interface GaugeArcConfig { /** Bar/track thickness in px. Auto-computed from radius if omitted. */ thickness?: number; cornerRadius?: number; - /** Gap between concentric bars (multiBar) or track/bar (px). */ - gap?: number; } export interface GaugeTrackConfig { @@ -35,14 +137,9 @@ export interface GaugeTrackConfig { color?: string; } +/** A flat color, or an array of 2+ colors to render as a gradient across the bar. */ export type GaugeColor = string | string[]; -export interface GaugeBarSpec { - value: number; - color?: GaugeColor; - label?: string; -} - export type NeedleType = "line" | "rounded" | "drop" | "triangle"; export interface GaugeNeedleConfig { @@ -56,11 +153,6 @@ export interface GaugeNeedleConfig { animation?: boolean; } -export interface GaugeLabelsConfig { - show?: boolean; - position?: "inside" | "outside"; -} - export interface GaugeValueLabelConfig { show?: boolean; precision?: number; @@ -69,45 +161,8 @@ export interface GaugeValueLabelConfig { formatter?: (value: number) => string; } -export interface GaugeNeedleLabelConfig { - show?: boolean; - formatter?: (value: number) => string; -} - -export interface GaugeScaleConfig { - minLabel?: string; - maxLabel?: string; -} - -export interface GaugeTicksConfig { - show?: boolean; - count?: number; - position?: "inside" | "outside" | "cross"; - length?: number; - labels?: boolean; -} - -export interface GaugeSegment { - from: number; - to: number; - color: GaugeColor; - } - - export interface GaugeThreshold { - value: number; - color: GaugeColor; - } - -export interface GaugeGradientConfig { - colors: string[]; -} - export interface GaugeAnimationConfig { duration?: number; /** Any d3-ease export name, e.g. "easeCubicOut", "easeElasticOut". */ easing?: string; -} - -export interface GaugeTooltipConfig { - show?: boolean; } \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 6ac6356c..e26b5c4f 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -2,7 +2,7 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "../../../dist/style.css"; +import "../../../dist/styles.css" const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = @@ -32,219 +32,313 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
- {/* ============================================================ - * 1. Default appearance β€” no theme, no styles, no - * formatting props. Every fallback in the widget in one place. - * ============================================================ */} - + //
+ // {/* ============================================================ + // * 1. Default appearance β€” no theme, no styles, no + // * formatting props. Every fallback in the widget in one place. + // * ============================================================ */} + // - {/* ============================================================ - * 2. theme β€” a reusable, shareable WidgetTheme object. Same - * effect across every widget instance that uses it. - * ============================================================ */} - + // {/* ============================================================ + // * 2. theme β€” a reusable, shareable WidgetTheme object. Same + // * effect across every widget instance that uses it. + // * ============================================================ */} + // - {/* Built-in preset names also work directly: */} - + // {/* Built-in preset names also work directly: */} + // - {/* ============================================================ - * 3. styles vs className β€” THE distinction to understand: - * - * - `styles` (plural, an OBJECT): per-SLOT overrides. - * Keys are "container" | "title" | "value" | "unit" | "label" - * β€” lets you reach INSIDE the widget and style individual - * pieces independently. - * - * - `className` (singular, a STRING): the ordinary React - * convention β€” one class applied ONLY to the widget's - * outermost container element, same as you'd pass to any - * other component. It's merged (via twMerge) with whatever - * styles.container already resolved to, not a - * replacement for it. - * - * This example uses BOTH at once so the difference is visible: - * className adds a shadow to the outer box, styles.value/ - * styles.title style two INNER pieces independently. - * ============================================================ */} - + // {/* ============================================================ + // * 3. styles vs className β€” THE distinction to understand: + // * + // * - `styles` (plural, an OBJECT): per-SLOT overrides. + // * Keys are "container" | "title" | "value" | "unit" | "label" + // * β€” lets you reach INSIDE the widget and style individual + // * pieces independently. + // * + // * - `className` (singular, a STRING): the ordinary React + // * convention β€” one class applied ONLY to the widget's + // * outermost container element, same as you'd pass to any + // * other component. It's merged (via twMerge) with whatever + // * styles.container already resolved to, not a + // * replacement for it. + // * + // * This example uses BOTH at once so the difference is visible: + // * className adds a shadow to the outer box, styles.value/ + // * styles.title style two INNER pieces independently. + // * ============================================================ */} + // - {/* ============================================================ - * 4. Plain CSS classes β€” classNames works with ANY class source, - * not just Tailwind. These reference plain hand-written CSS - * classes (e.g. defined in a .css file this app already imports). - * ============================================================ */} - + // {/* ============================================================ + // * 4. Plain CSS classes β€” classNames works with ANY class source, + // * not just Tailwind. These reference plain hand-written CSS + // * classes (e.g. defined in a .css file this app already imports). + // * ============================================================ */} + // - {/* ============================================================ - * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` - * work exactly as they do anywhere else in your app, because - * classNames just forwards whatever string you write straight - * to `className`. This widget does NOT have its own custom - * breakpoint system β€” these prefixes are compiled by YOUR - * project's Tailwind config and respond to the BROWSER VIEWPORT, - * same as native Tailwind everywhere else. If your own - * tailwind.config.js customizes `theme.screens`, these prefixes - * automatically follow that customization too β€” nothing to - * configure on the widget's side. - * ============================================================ */} - + // {/* ============================================================ + // * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` + // * work exactly as they do anywhere else in your app, because + // * classNames just forwards whatever string you write straight + // * to `className`. This widget does NOT have its own custom + // * breakpoint system β€” these prefixes are compiled by YOUR + // * project's Tailwind config and respond to the BROWSER VIEWPORT, + // * same as native Tailwind everywhere else. If your own + // * tailwind.config.js customizes `theme.screens`, these prefixes + // * automatically follow that customization too β€” nothing to + // * configure on the widget's side. + // * ============================================================ */} + // - {/* ============================================================ - * 3. Segmented variant β€” colored ranges (risk zones), with - * needle enabled to point at the current value (like your - * ChartExpo reference image). - * ============================================================ */} - `${v.toFixed(2)} % RH`} - labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - /> + // {/* ============================================================ + // * 3. Segmented variant β€” colored ranges (risk zones), with + // * needle enabled to point at the current value (like your + // * ChartExpo reference image). + // * ============================================================ */} + // `${v.toFixed(2)} % RH`} + // labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} + // /> - {/* ============================================================ - * 7. onStyleChange β€” conditional class overrides driven by the - * RAW fetched data ({ value, timestamp }), always applied on top - * of everything else (theme, classNames, className). - * ============================================================ */} - { - if (!data) return; + // {/* ============================================================ + // * 7. onStyleChange β€” conditional class overrides driven by the + // * RAW fetched data ({ value, timestamp }), always applied on top + // * of everything else (theme, classNames, className). + // * ============================================================ */} + // { + // if (!data) return; - if (data.value > 80) { - return { - title: "High Humidity", - theme: "dark", - classNames: { - value: "text-red-500", - }, - }; - } + // if (data.value > 80) { + // return { + // title: "High Humidity", + // theme: "dark", + // classNames: { + // value: "text-red-500", + // }, + // }; + // } - return { - title: "Humidity", - theme: "light", - }; - }} - /> + // return { + // title: "Humidity", + // theme: "light", + // }; + // }} + // /> - {/* ============================================================ - * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, - * applied as inline styles on the container, independent of the - * whole classNames/theme system. - * ============================================================ */} - + // {/* ============================================================ + // * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, + // * applied as inline styles on the container, independent of the + // * whole classNames/theme system. + // * ============================================================ */} + // - { + // "Hello"; + // }, + // }} + // labels={{ + // show: true, + // position: "outside", + // }} + // scale={{ + // minLabel: "Minimum", + // maxLabel: "Maximum", + // }} + // ticks={{ + // show: true, + // count: 10, + // position: "outside", + // length: 10, + // labels: true, + // }} + // animation={{ + // duration: 5000, + // easing: "easeElasticOut", + // }} + // tooltip={{ + // show: false, + // }} + // classNames={{ + // title: "text-white", + // tickLabel: "text-white text-lg", + // label: "text-white", + // value: "text-white", + // }} + // /> + //
+
+ + {/* { - "Hello"; - }, - }} - labels={{ - show: true, - position: "outside", - }} - scale={{ - minLabel: "Minimum", - maxLabel: "Maximum", - }} - ticks={{ - show: true, - count: 10, - position: "outside", - length: 10, - labels: true, - }} + // needleLabel={{ + // show: true, + // formatter: () => { + // "Hello"; + // }, + // }} + // labels={{ + // show: true, + // position: "outside", + // }} + // scale={{ + // minLabel: "Hello", + // maxLabel: "World", + // }} + // ticks={{ + // show: true, + // count: 10, + // position: "outside", + // length: 10, + // labels: true, + // }} animation={{ - duration: 5000, - easing: "easeElasticOut", - }} - tooltip={{ - show: false, + duration: 4000, + easing: "easeElasticOut", // easeCubicOut, easeElasticOut }} - classNames={{ - title: "text-white", - tickLabel: "text-white text-lg", - label: "text-white", - value: "text-white", - }} - /> + // tooltip={{ + // show:false, + // }} + // classNames={{ + // title: "text-white", + // tickLabel: "text-white text-lg", + // label: "text-red", + // value: "text-white", + // }} + theme="dark" + /> */} + +
); } From 03c51f93062fbe5f0ce86aeb0fea6aa523fc2e93 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 17:00:49 +0530 Subject: [PATCH 37/66] remove old code --- src/components/Bar Chart/BarChartWidgets.tsx | 626 ------------------ .../GaugeChart/GaugeChartWidget.tsx | 606 +++++++++++++---- src/components/StreamWidgets.tsx | 73 -- src/components/chartTheme.tsx | 240 ------- test/my-app/src/App.jsx | 387 +++++------ 5 files changed, 630 insertions(+), 1302 deletions(-) delete mode 100644 src/components/Bar Chart/BarChartWidgets.tsx delete mode 100644 src/components/StreamWidgets.tsx delete mode 100644 src/components/chartTheme.tsx diff --git a/src/components/Bar Chart/BarChartWidgets.tsx b/src/components/Bar Chart/BarChartWidgets.tsx deleted file mode 100644 index b06b2123..00000000 --- a/src/components/Bar Chart/BarChartWidgets.tsx +++ /dev/null @@ -1,626 +0,0 @@ -import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; -import * as d3 from "d3"; -import { validateRequiredProps } from "../../helpers/validate"; -import { - defaultDateFormatter, - formatDate, - formatNumber, -} from "../../helpers/formatDate"; -import { - ChartStyleSet, - ThemeName, - DEFAULT_THEME, - themes, - mergeStyleSets, - ResponsiveStyleSet, - resolveResponsiveStyle, -} from "../chartTheme"; - -export type { - ChartStyleSet, - ThemeName, - ResponsiveStyleSet, - Breakpoint, -} from "../chartTheme"; -export { - defineStyleRules, - lightTheme, - darkTheme, - themes, - BREAKPOINTS, -} from "../chartTheme"; - -/* ------------------------ Types ------------------------ */ - -export interface BarDataPoint { - name: string; - value: number; -} - -type WidgetState = { - data: BarDataPoint[]; - loading: boolean; - error: string | null; -}; - -type StylesInput = ChartStyleSet | ((state: WidgetState) => ChartStyleSet); - -export interface BarChartWidgetProps { - client?: any; - nodeId?: string; - variable?: string; - from?: number; - to?: number; - limit?: number; - title?: string; - theme?: ThemeName; - styles?: StylesInput; - responsiveStyles?: ResponsiveStyleSet; - tooltipFormat?: (d: BarDataPoint) => string; - // tickCount?: number; - xTickCount?: number | "max"; - yTickCount?: number; - // xTickFormat?: string | ((d: Date) => string); - xTickFormat?: (d: BarDataPoint) => string; - yTickFormat?: string | ((v: number) => string); - onStyleChange?: (data: BarDataPoint[]) => ChartStyleSet | void; - width?: number; - height?: number; - aspectRatio?: number; - minWidth?: number; - maxWidth?: number; - minHeight?: number; - maxHeight?: number; - /** - * Minimum width (px) reserved per bar (bar + its gap). If - * `data.length * minBarWidth` would exceed the space actually - * available (container width, or `width` if fixed), the chart - * renders at its natural, larger width and the wrapper becomes - * horizontally scrollable instead of squeezing bars into - * unreadable slivers. Defaults to 32. - */ - minBarWidth?: number; - /** - * TEMP: dummy data source until the real API/client is wired up. - * If omitted and no `client` is provided, `generateDummyData(limit)` - * is used automatically so the widget renders out of the box. - */ - data?: BarDataPoint[]; -} - -const FALLBACK_WIDTH = 800; -const DEFAULT_ASPECT_RATIO = 800 / 500; -const MARGIN = { top: 16, right: 16, bottom: 36, left: 44 }; - -const DEFAULT_MIN_WIDTH = 280; -const DEFAULT_MAX_WIDTH = 1200; -const DEFAULT_MIN_HEIGHT = 200; -const DEFAULT_MAX_HEIGHT = 700; -const DEFAULT_MIN_BAR_WIDTH = 32; - -const clamp = (value: number, min: number, max: number) => - Math.min(Math.max(value, min), max); -const toDateSafe = (ts: number): Date => - ts < 1e12 ? new Date(ts * 1000) : new Date(ts); - -/** TEMP helper β€” swap out once the real API is connected. */ -export function generateDummyData(count = 12): BarDataPoint[] { - return Array.from({ length: count }, (_, i) => ({ - name: `Item ${i + 1}`, - value: Math.round(20 + Math.random() * 80), - })); -} - -/* ------------------------ BarChartWidget ------------------------ */ -export const BarChartWidget: React.FC = ({ - client, - nodeId, - variable, - from, - to, - limit = 12, - title = "Latest Data", - theme = DEFAULT_THEME, - styles = {}, - responsiveStyles, - tooltipFormat, - xTickCount = "max", - yTickCount = 4, - xTickFormat, - yTickFormat, - onStyleChange, - width: fixedWidth, - height: fixedHeight, - aspectRatio = DEFAULT_ASPECT_RATIO, - minWidth = DEFAULT_MIN_WIDTH, - maxWidth = DEFAULT_MAX_WIDTH, - minHeight = DEFAULT_MIN_HEIGHT, - maxHeight = DEFAULT_MAX_HEIGHT, - minBarWidth = DEFAULT_MIN_BAR_WIDTH, - data: dataProp, -}) => { - // client/nodeId/variable/from/to are only required once this widget is - // actually wired to the API. While using dummy/passed-in data, skip the - // validation entirely. - const usingRealClient = !dataProp && !!client; - if (usingRealClient) { - validateRequiredProps( - "Bar Chart Widget", - { client, nodeId, variable, from, to }, - ["client", "nodeId", "variable", "from time", "to time"] - ); - } - - /* ---------------- Responsive sizing (same approach as ChartWidget) ---------------- */ - const containerRef = useRef(null); - const [measuredWidth, setMeasuredWidth] = useState(FALLBACK_WIDTH); - - useLayoutEffect(() => { - if (fixedWidth != null) return; - const el = containerRef.current; - if (!el || typeof ResizeObserver === "undefined") return; - - const observer = new ResizeObserver((entries) => { - const entry = entries[0]; - if (!entry) return; - const w = Math.round(entry.contentRect.width); - if (w > 0) setMeasuredWidth(w); - }); - - observer.observe(el); - return () => observer.disconnect(); - }, [fixedWidth]); - - const availableWidth = fixedWidth ?? clamp(measuredWidth, minWidth, maxWidth); - const effectiveHeight = - fixedHeight ?? - clamp(Math.round(availableWidth / aspectRatio), minHeight, maxHeight); - - /* ---------------- Data (client fetch OR dummy/passed-in) ---------------- */ - const [node, setNode] = useState(null); - const [data, setData] = useState( - dataProp ?? (usingRealClient ? [] : generateDummyData(limit)) - ); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - - const mountedRef = useRef(false); - const isFetchingRef = useRef(false); - - useEffect(() => { - if (!usingRealClient) return; - const anedya = client._anedya; - setNode(anedya?.newNode?.(client, nodeId) ?? null); - }, [usingRealClient, client, nodeId]); - - useEffect(() => { - if (dataProp) { - setData(dataProp); - return; - } - if (!usingRealClient || !node) return; - mountedRef.current = true; - - const fetchData = async () => { - if (isFetchingRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - - try { - const res = await node.getData({ - variable, - from, - to, - limit, - order: "asc", - }); - if (!mountedRef.current) return; - - if (res.isSuccess && res.isDataAvailable) { - setData(res.data); - } else { - setData([]); - setError(res.error?.errorMessage ?? "No data available"); - } - } catch (err: any) { - if (!mountedRef.current) return; - setData([]); - setError(err?.message ?? "Failed to fetch data"); - } finally { - if (mountedRef.current) { - setLoading(false); - isFetchingRef.current = false; - } - } - }; - - fetchData(); - return () => { - mountedRef.current = false; - }; - }, [dataProp, usingRealClient, node, variable, from, to, limit]); - - /* ---------------- Styling (identical precedence to ChartWidget) ---------------- */ - const [dynamicStyle, setDynamicStyle] = useState({}); - - useEffect(() => { - const fromStylesProp = - typeof styles === "function" ? styles({ data, loading, error }) : styles; - const fromCallback = onStyleChange?.(data) ?? {}; - - setDynamicStyle(mergeStyleSets(fromStylesProp, fromCallback)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data]); - - const resolvedStyle = useMemo( - () => - mergeStyleSets( - { chart: themes[theme] }, - dynamicStyle, - resolveResponsiveStyle(responsiveStyles, availableWidth) - ), - [theme, dynamicStyle, responsiveStyles, availableWidth] - ); - // `barColor`, `barHoverColor`, `barRadius`, `tooltipBg`, `tooltipColor` are - // the new optional tokens added to chartTheme.ts β€” see instructions. - const chartStyle: any = resolvedStyle.chart!; - - /* ---------------- Overflow / scroll logic ---------------- */ - const idealContentWidth = - MARGIN.left + MARGIN.right + Math.max(data.length, 1) * minBarWidth; - const needsScroll = idealContentWidth > availableWidth; - const effectiveWidth = needsScroll ? idealContentWidth : availableWidth; - - const CHART_W = effectiveWidth - MARGIN.left - MARGIN.right; - const CHART_H = effectiveHeight - MARGIN.top - MARGIN.bottom; - - const effectiveXTickCount = - xTickCount === "max" - ? data.length - : effectiveWidth < 380 - ? Math.min(xTickCount, 2) - : effectiveWidth < 560 - ? Math.min(xTickCount, 3) - : xTickCount; - - const { bars, xTicks, yTicks } = useMemo(() => { - if (!data.length) { - return { - bars: [] as { - x: number; - y: number; - w: number; - h: number; - point: BarDataPoint; - }[], - xTicks: [], - yTicks: [], - }; - } - - const x = d3 - .scaleBand() - .domain(data.map((_, i) => i)) - .range([0, CHART_W]) - .padding(0.35); - - const maxY = Math.max(10, d3.max(data, (d) => d.value) ?? 10); - const y = d3.scaleLinear().domain([0, maxY]).nice().range([CHART_H, 0]); - - const bars = data.map((d, i) => ({ - x: x(i) ?? 0, - y: y(d.value), - w: x.bandwidth(), - h: CHART_H - y(d.value), - point: d, - })); - - // Thin out x labels the same way ChartWidget thins ticks, but on - // categorical indices instead of a continuous time scale. - const labelStep = Math.max(1, Math.ceil(data.length / effectiveXTickCount)); - - const xTicks = data - .map((d, i) => ({ i, d })) - .filter(({ i }) => i % labelStep === 0) - .map(({ i, d }) => ({ - x: (x(i) ?? 0) + x.bandwidth() / 2, - label: xTickFormat ? xTickFormat(d) : d.name, - })); - - const yTicks = y.ticks(yTickCount).map((v) => ({ - y: y(v), - label: - typeof yTickFormat === "function" - ? yTickFormat(v) - : typeof yTickFormat === "string" - ? formatNumber(v, yTickFormat) - : String(v), - })); - - return { bars, xTicks, yTicks }; - }, [ - data, - effectiveXTickCount, - yTickCount, - xTickFormat, - yTickFormat, - CHART_W, - CHART_H, - ]); - - /* ---------------- Custom D3-driven tooltip (no Base UI) ---------------- */ - const [hover, setHover] = useState<{ - x: number; - y: number; - point: BarDataPoint; - } | null>(null); - - return ( -
- {title && ( -

- {title} -

- )} - - {loading ? ( -
-
- -
- ) : error ? ( -
-
- {error} -
-
- ) : data.length === 0 ? ( -
- No data available -
- ) : ( - // `overflowX: auto` only kicks in once bars would otherwise be - // squeezed below `minBarWidth` β€” otherwise this behaves exactly - // like ChartWidget's fluid 100%-width svg. -
- - - {/* X axis */} - - {xTicks.map((t, i) => ( - - {t.label} - - ))} - - {/* Y axis */} - {yTicks.map((t, i) => ( - - {t.label} - - ))} - - {/* X axis */} - - - {/* Y axis */} - - - {bars.map(({ x, y, w, h, point }, i) => { - const isHovered = hover?.point === point; - return ( - - { - const rect = ( - e.currentTarget.ownerSVGElement as SVGSVGElement - ).getBoundingClientRect(); - setHover({ - x: e.clientX - rect.left, - y: e.clientY - rect.top, - point, - }); - }} - onMouseMove={(e) => { - const rect = ( - e.currentTarget.ownerSVGElement as SVGSVGElement - ).getBoundingClientRect(); - setHover({ - x: e.clientX - rect.left, - y: e.clientY - rect.top, - point, - }); - }} - onMouseLeave={() => setHover(null)} - /> - - {point.value} - - - ); - })} - - - - {/* Plain-div tooltip, positioned via the mouse coords captured - above β€” replaces Base UI's Tooltip.* primitives entirely. */} - {hover && ( -
- {tooltipFormat - ? tooltipFormat(hover.point) - : `${hover.point.name}: ${hover.point.value}`} -
- )} -
- )} -
- ); -}; - -// TODO: swap generateDummyData() usage for real API data once client wiring -// is ready β€” just start passing `client`/`nodeId`/`variable`/`from`/`to` -// (or your own `data` prop) and the dummy fallback stops being used. diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index bb233012..c1c42315 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -145,7 +145,7 @@ // default: { // const half = w / 2; // // Teardrop: rounded base, sharp tip. -// const d = `M ${-half} 0 +// const d = `M ${-half} 0 // C ${-half} ${-length * 0.35}, ${-w} ${ // -length * 0.7 // }, 0 ${-length} @@ -928,12 +928,15 @@ // ); // } - - import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import * as d3 from "d3"; import { twMerge } from "tailwind-merge"; -import { AnedyaWidgetBaseProps } from "../../common"; +import { + AnedyaWidgetBaseProps, + FormatOptions, + FormatPreset, + LabelFormatPreset, +} from "../../common"; import { SlotClassNames, WidgetTheme } from "../../types/root"; import { GaugeAnimationConfig, @@ -951,9 +954,19 @@ import { gaugeLightTheme, } from "../../themes/gaugeTheme"; import { useResizeObserver } from "../../hooks/useResizeObserver"; +import { FORMATTERS, LABEL_FORMATTERS } from "../../helpers/formatters"; + +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +export interface GaugeData { + value: number; + timestamp: number; +} + +export type GaugeWidgetUpdate = Partial< + Omit +>; export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { - /** Used before live data arrives, or standalone in dummy-data mode. */ value?: number; min?: number; max?: number; @@ -962,18 +975,27 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { arc?: GaugeArcConfig; track?: GaugeTrackConfig; - /** Bar fill color. Pass an array of 2+ colors for a gradient. */ color?: GaugeColor; needle?: GaugeNeedleConfig; valueLabel?: GaugeValueLabelConfig; animation?: GaugeAnimationConfig; - classNames?: SlotClassNames; + // ---- Card-parity formatting props ---- + unit?: string; + decimalPlaces?: number; + formatValue?: (value: number) => string; + format?: FormatPreset; + formatOptions?: FormatOptions; + labelText?: (timestamp: number) => string; + labelFormat?: LabelFormatPreset; + + styles?: SlotClassNames; style?: React.CSSProperties; onClick?: (value: number) => void; onValueChange?: (value: number) => void; + onDataChange?: (data: GaugeData | null) => GaugeWidgetUpdate | void; } const DEG2RAD = Math.PI / 180; @@ -989,16 +1011,17 @@ const DEFAULT_ANIMATION: Required = { easing: "easeCubicOut", }; -// A dome (semicircle-ish) gauge only uses the top half of its box, so its -// natural height:width ratio is well under 1. This is the fallback used -// when no explicit height/aspectRatio is given. +const DEFAULT_WIDTH = 240; const DEFAULT_HEIGHT_RATIO = 0.68; function resolveEase(name: string) { return (d3 as any)[name] ?? d3.easeCubicOut; } -function needlePixelLength(length: GaugeNeedleConfig["length"], radius: number) { +function needlePixelLength( + length: GaugeNeedleConfig["length"], + radius: number +) { if (typeof length === "number") return length; switch (length) { case "short": @@ -1011,32 +1034,55 @@ function needlePixelLength(length: GaugeNeedleConfig["length"], radius: number) } } -/** Builds a needle shape pointing "up" (-y) from the origin; rotated into place via a group transform. */ -function needleShape(type: NonNullable, length: number, width: number) { +function needleShape( + type: NonNullable, + length: number, + width: number +) { const w = width; switch (type) { case "line": return { tag: "line", - attrs: { x1: 0, y1: 0, x2: 0, y2: -length, strokeWidth: w, strokeLinecap: "butt" }, + attrs: { + x1: 0, + y1: 0, + x2: 0, + y2: -length, + strokeWidth: w, + strokeLinecap: "butt", + }, }; case "rounded": return { tag: "line", - attrs: { x1: 0, y1: 0, x2: 0, y2: -length, strokeWidth: w, strokeLinecap: "round" }, + attrs: { + x1: 0, + y1: 0, + x2: 0, + y2: -length, + strokeWidth: w, + strokeLinecap: "round", + }, }; case "triangle": { const half = w / 2; return { tag: "polygon", - attrs: { points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${-length * 0.15}` }, + attrs: { + points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ + -length * 0.15 + }`, + }, }; } case "drop": default: { const half = w / 2; const d = `M ${-half} 0 - C ${-half} ${-length * 0.35}, ${-w} ${-length * 0.7}, 0 ${-length} + C ${-half} ${-length * 0.35}, ${-w} ${ + -length * 0.7 + }, 0 ${-length} C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 A ${half} ${half} 0 1 1 ${-half} 0 Z`; return { tag: "path", attrs: { d } }; @@ -1048,7 +1094,6 @@ function isGradientColor(c?: GaugeColor): c is string[] { return Array.isArray(c) && c.length >= 2; } -/** Ensures a with the given id/colors exists in and returns its url() reference. */ function resolveFill( defs: d3.Selection, id: string, @@ -1073,14 +1118,16 @@ function resolveFill( return `url(#${id})`; } -/** Normalized (r=1) bounding box of an arc sweep β€” handles semicircle, 270Β°, full circle, custom. */ function getArcBounds(startDeg: number, endDeg: number) { const lo = Math.min(startDeg, endDeg); const hi = Math.max(startDeg, endDeg); const angles = [startDeg, endDeg]; for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); - let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; + let minX = Infinity, + maxX = -Infinity, + minY = Infinity, + maxY = -Infinity; angles.forEach((deg) => { const a = deg * DEG2RAD; const x = Math.sin(a); @@ -1096,7 +1143,7 @@ function getArcBounds(startDeg: number, endDeg: number) { export function GaugeWidget({ node, variable, - title, + title = "Latest Value", theme, className, style, @@ -1122,37 +1169,87 @@ export function GaugeWidget({ valueLabel, animation, - classNames = {}, + unit, + decimalPlaces, + formatValue, + format, + formatOptions, + labelText, + labelFormat, + + styles = {}, onClick, onValueChange, + onDataChange, }: GaugeWidgetProps) { const svgRef = useRef(null); - const prevValueRef = useRef(min); + // const prevValueRef = useRef(min); const [fetchedValue, setFetchedValue] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const [dynamicProps, setDynamicProps] = useState({}); - // ---- Live data fetch (mirrors CardWidget) ---- + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + + // ---- Live data fetch (mirrors CardWidget, plus timestamp) ---- useEffect(() => { if (!node) return; - let mounted = true; + mountedRef.current = true; + + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + + try { + const res = await node.getLatestData(variable); + if (!mountedRef.current) return; - node - .getLatestData(variable) - .then((res: any) => { - if (!mounted) return; - if (res?.isSuccess && res?.isDataAvailable) { + if (res.isSuccess && res.isDataAvailable) { setFetchedValue(res.data.value); + setTimestamp(res.data.timestamp); + } else { + setFetchedValue(null); + setError(res.error?.errorMessage ?? "No data available"); } - }) - .catch(() => { - /* fall back to `value` prop / dummy data silently */ - }); + } catch (err: any) { + if (!mountedRef.current) return; + setFetchedValue(null); + setError(err?.message ?? "Failed to fetch data"); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + fetchLatest(); return () => { - mounted = false; + mountedRef.current = false; }; }, [node, variable]); + // ---- onDataChange resolution (identical pattern to CardWidget) ---- + useEffect(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + + const data = + fetchedValue != null && timestamp != null + ? { value: fetchedValue, timestamp } + : null; + + setDynamicProps(onDataChange(data) ?? {}); + }, [fetchedValue, timestamp, onDataChange]); + const rawValue = fetchedValue ?? valueProp ?? min; const clampedValue = Math.min(max, Math.max(min, rawValue)); @@ -1160,63 +1257,154 @@ export function GaugeWidget({ onValueChange?.(clampedValue); }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps - // ---- Responsive sizing ---- - // Disabled once `size` is set, since that fixes both dimensions explicitly. const { ref: wrapperRef, size: dims } = useResizeObserver( responsive && size == null ); + const mergedStyles = useMemo( + () => ({ ...(styles ?? {}), ...(dynamicProps.styles ?? {}) }), + [styles, dynamicProps.styles] + ); + + // ---- Merge static props with dynamic onDataChange overrides ---- + const resolvedProps = { + title, + theme, + className, + width, + height, + minWidth, + maxWidth, + minHeight, + maxHeight, + aspectRatio, + min, + max, + size, + responsive, + arc, + track, + color, + needle, + valueLabel, + animation, + unit, + decimalPlaces, + formatValue, + format, + formatOptions, + labelText, + labelFormat, + ...dynamicProps, + styles: mergedStyles, + }; + // ---- Resolved config ---- - const resolvedArc = { ...DEFAULT_ARC, ...arc }; + const resolvedArc = { ...DEFAULT_ARC, ...resolvedProps.arc }; const resolvedTrack: Required = { - show: track?.show ?? true, - color: track?.color ?? "", + show: resolvedProps.track?.show ?? true, + color: resolvedProps.track?.color ?? "", }; const resolvedNeedle: Required> & { length: NonNullable; } = { - show: needle?.show ?? true, - type: needle?.type ?? "rounded", - length: needle?.length ?? "medium", - width: needle?.width ?? 4, - color: needle?.color ?? "", - capRadius: needle?.capRadius ?? 6, - animation: needle?.animation ?? true, + show: resolvedProps.needle?.show ?? true, + type: resolvedProps.needle?.type ?? "rounded", + length: resolvedProps.needle?.length ?? "medium", + width: resolvedProps.needle?.width ?? 4, + color: resolvedProps.needle?.color ?? "", + capRadius: resolvedProps.needle?.capRadius ?? 6, + animation: resolvedProps.needle?.animation ?? true, }; - const resolvedValueLabel: Required> & { - formatter?: (v: number) => string; - } = { - show: valueLabel?.show ?? true, - precision: valueLabel?.precision ?? 0, - prefix: valueLabel?.prefix ?? "", - suffix: valueLabel?.suffix ?? "", - formatter: valueLabel?.formatter, + const resolvedValueLabel: Required> = { + show: resolvedProps.valueLabel?.show ?? true, }; - const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; + const resolvedAnimation = { + ...DEFAULT_ANIMATION, + ...resolvedProps.animation, + }; - // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- + // ---- Theme + slot classes ---- const resolvedTheme: WidgetTheme = - theme === "dark" + resolvedProps.theme === "dark" ? gaugeDarkTheme - : theme === "light" + : resolvedProps.theme === "light" ? gaugeLightTheme - : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; + : (resolvedProps.theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; const resolveSlot = useCallback( (slot: GaugeSlot) => - twMerge(GAUGE_DEFAULT_CLASSES[slot], resolvedTheme.styles[slot], classNames[slot]), - [resolvedTheme, classNames] + twMerge( + GAUGE_DEFAULT_CLASSES[slot], + resolvedTheme.styles[slot], + resolvedProps.styles[slot] + ), + [resolvedTheme, resolvedProps.styles] ); + // ---- Value + unit formatting (same precedence as CardWidget) ---- + const { displayValue, displayUnit } = useMemo(() => { + if (resolvedProps.formatValue) { + return { + displayValue: resolvedProps.formatValue(clampedValue), + displayUnit: resolvedProps.unit, + }; + } + + if (resolvedProps.format) { + const result = FORMATTERS[resolvedProps.format]( + clampedValue, + resolvedProps.formatOptions + ); + return { displayValue: result.value, displayUnit: result.unit }; + } + + if (resolvedProps.decimalPlaces != null) { + return { + displayValue: clampedValue.toFixed(resolvedProps.decimalPlaces), + displayUnit: resolvedProps.unit, + }; + } + + return { + displayValue: String(clampedValue), + displayUnit: resolvedProps.unit, + }; + }, [ + clampedValue, + resolvedProps.formatValue, + resolvedProps.format, + resolvedProps.formatOptions, + resolvedProps.decimalPlaces, + resolvedProps.unit, + ]); + + // ---- Last-updated label β€” THIS is what shows the time ---- + const displayLabel = useMemo(() => { + if (timestamp == null) return null; + + if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); + + const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; + return formatter(timestamp, resolvedProps.formatOptions?.locale); + }, [ + timestamp, + resolvedProps.labelText, + resolvedProps.labelFormat, + resolvedProps.formatOptions?.locale, + ]); + // ---- Geometry ---- - // `size` fixes both dimensions in real CSS px so the wrapper's rendered - // box exactly matches the SVG viewBox (boxWidth === boxHeight === size). - const boxWidth = size ?? width ?? (dims.width || 240); - const boxHeight = size ?? height ?? (dims.height || boxWidth * DEFAULT_HEIGHT_RATIO); + const boxWidth = + resolvedProps.size ?? resolvedProps.width ?? (dims.width || DEFAULT_WIDTH); + const boxHeight = + resolvedProps.size ?? + resolvedProps.height ?? + (dims.height || boxWidth * DEFAULT_HEIGHT_RATIO); const bounds = useMemo( () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), @@ -1224,9 +1412,8 @@ export function GaugeWidget({ ); const pad = 8; - // Reserve room below the arc for the value + label text so the dome - // never gets crowded. - const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + // const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + const textReserve = 0; const availW = boxWidth - pad * 2; const availH = boxHeight * (1 - textReserve) - pad * 2; @@ -1235,26 +1422,32 @@ export function GaugeWidget({ Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1)) ); - // An explicit `arc.radius` is honored, but clamped so the arc can never - // overflow the container and get clipped by the SVG viewBox. const outerRadius = resolvedArc.radius ? Math.min(resolvedArc.radius, maxFitRadius) : maxFitRadius; const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); - // Center the arc's bounding box within the available width, anchor its top at `pad`. - const cx = pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; + const cx = + pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; const cy = pad - bounds.minY * outerRadius; const angleScale = useMemo( () => d3 .scaleLinear() - .domain([min, max]) - .range([resolvedArc.startAngle * DEG2RAD, resolvedArc.endAngle * DEG2RAD]) + .domain([resolvedProps.min, resolvedProps.max]) + .range([ + resolvedArc.startAngle * DEG2RAD, + resolvedArc.endAngle * DEG2RAD, + ]) .clamp(true), - [min, max, resolvedArc.startAngle, resolvedArc.endAngle] + [ + resolvedProps.min, + resolvedProps.max, + resolvedArc.startAngle, + resolvedArc.endAngle, + ] ); // ---- D3 draw ---- @@ -1267,8 +1460,6 @@ export function GaugeWidget({ root.attr("transform", `translate(${cx},${cy})`); const ease = resolveEase(resolvedAnimation.easing); - // A cornerRadius larger than half the bar's thickness produces - // self-intersecting, glitchy arcs β€” clamp it to a safe maximum. const safeCornerRadius = Math.min(resolvedArc.cornerRadius, thickness / 2); const arcGen = d3 @@ -1282,37 +1473,52 @@ export function GaugeWidget({ const startA = resolvedArc.startAngle * DEG2RAD; const endA = resolvedArc.endAngle * DEG2RAD; - // --- Track --- - const trackSel = root.select("path.anedya-gauge-track-path"); + const trackSel = root.select( + "path.anedya-gauge-track-path" + ); if (resolvedTrack.show) { trackSel - .attr("d", arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })!) + .attr( + "d", + arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! + ) .attr("fill", resolvedTrack.color || "currentColor") .attr("opacity", 1); } else { trackSel.attr("opacity", 0); } - // --- Bar (animated fill toward the current value) --- const barGroup = root.select("g.anedya-gauge-bar-group"); - barGroup.selectAll("*").remove(); - const valueAngle = angleScale(clampedValue); - const barFill = resolveFill(defs, "anedya-gauge-bar-fill", color, "currentColor"); + const barValue = loading || error ? resolvedProps.min : clampedValue; + const valueAngle = angleScale(barValue); + const barFill = resolveFill( + defs, + "anedya-gauge-bar-fill", + resolvedProps.color, + "currentColor" + ); + + let path = barGroup.select("path.anedya-gauge-bar-path"); + if (path.empty()) { + path = barGroup + .append("path") + .attr("class", "anedya-gauge-bar-path") + .attr("data-end-angle", String(startA)); + } - const path = barGroup - .append("path") - .attr("class", resolveSlot("bar")) + path + .attr("class", twMerge("anedya-gauge-bar-path", resolveSlot("bar"))) .attr("fill", barFill) - .attr("stroke", "none"); + .attr("stroke", "none") + .attr("opacity", loading ? 0.4 : 1); + + const currentEndAngle = path.attr("data-end-angle") + ? +path.attr("data-end-angle")! + : startA; path - .datum({ - startAngle: startA, - endAngle: - prevValueRef.current != null ? angleScale(prevValueRef.current) : startA, - r: outerRadius, - }) + .datum({ startAngle: startA, endAngle: currentEndAngle, r: outerRadius }) .transition() .duration(resolvedAnimation.duration) .ease(ease) @@ -1320,33 +1526,52 @@ export function GaugeWidget({ const interp = d3.interpolate(d.endAngle, valueAngle); return (t) => { d.endAngle = interp(t); - return arcGen({ startAngle: startA, endAngle: d.endAngle, r: outerRadius })!; + path.attr("data-end-angle", String(d.endAngle)); + return arcGen({ + startAngle: startA, + endAngle: d.endAngle, + r: outerRadius, + })!; }; }); - // --- Needle --- const needleGroup = root.select("g.anedya-gauge-needle"); if (resolvedNeedle.show) { const len = needlePixelLength(resolvedNeedle.length, outerRadius); const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); - const needleEl = needleGroup.insert(shape.tag as any, "circle.anedya-gauge-needle-cap"); + const needleEl = needleGroup.insert( + shape.tag as any, + "circle.anedya-gauge-needle-cap" + ); needleEl .attr("class", resolveSlot("needle")) .attr("fill", resolvedNeedle.color || "currentColor") - .attr("stroke", resolvedNeedle.color || "currentColor"); + .attr("stroke", resolvedNeedle.color || "currentColor") + .attr("opacity", loading ? 0.4 : 1); Object.entries(shape.attrs).forEach(([k, v]) => - needleEl.attr(k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), v as any) + needleEl.attr( + k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), + v as any + ) ); - let cap = needleGroup.select("circle.anedya-gauge-needle-cap"); + let cap = needleGroup.select( + "circle.anedya-gauge-needle-cap" + ); if (cap.empty()) { cap = needleGroup .append("circle") - .attr("class", twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap"))); + .attr( + "class", + twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) + ); } - cap.attr("r", resolvedNeedle.capRadius).attr("fill", resolvedNeedle.color || "currentColor"); + cap + .attr("r", resolvedNeedle.capRadius) + .attr("fill", resolvedNeedle.color || "currentColor") + .attr("opacity", loading ? 0.4 : 1); const targetDeg = valueAngle / DEG2RAD; if (resolvedNeedle.animation) { @@ -1366,14 +1591,16 @@ export function GaugeWidget({ }; }); } else { - needleGroup.attr("transform", `rotate(${targetDeg})`).attr("data-angle", String(targetDeg)); + needleGroup + .attr("transform", `rotate(${targetDeg})`) + .attr("data-angle", String(targetDeg)); } needleGroup.attr("opacity", 1); } else { needleGroup.attr("opacity", 0); } - prevValueRef.current = clampedValue; + // prevValueRef.current = barValue; }, [ boxWidth, boxHeight, @@ -1382,9 +1609,11 @@ export function GaugeWidget({ outerRadius, thickness, clampedValue, - min, - max, - color, + loading, + error, + resolvedProps.min, + resolvedProps.max, + resolvedProps.color, resolvedArc.cornerRadius, resolvedTrack.show, resolvedTrack.color, @@ -1400,30 +1629,38 @@ export function GaugeWidget({ resolveSlot, ]); - const handleClick = useCallback(() => onClick?.(clampedValue), [onClick, clampedValue]); - - const formattedValue = resolvedValueLabel.formatter - ? resolvedValueLabel.formatter(clampedValue) - : `${resolvedValueLabel.prefix}${clampedValue.toFixed(resolvedValueLabel.precision)}${resolvedValueLabel.suffix}`; + const handleClick = useCallback( + () => onClick?.(clampedValue), + [onClick, clampedValue] + ); return (
- {title && {title}} + {resolvedProps.title && ( + {resolvedProps.title} + )} - {resolvedValueLabel.show && ( - {formattedValue} + {loading ? ( +
+
+
+
+ ) : error ? ( + {error} + ) : ( + <> + {resolvedValueLabel.show && ( + + {displayValue} + {displayUnit && ( + {displayUnit} + )} + + )} + + {displayLabel && ( + {displayLabel} + )} + )} - {variable && {variable}} + {/* + {loading ? ( + // Loading skeletons inside SVG + <> + + + + ) : error ? ( + + {error} + + ) : ( + <> + {/* Value + Unit */} + {/* + {displayValue} + {displayUnit && ( + + {displayUnit} + + )} + */} + + {/* Label (timestamp) */} + {/* {displayLabel && ( + + {displayLabel} + + )} */} + {/* */} + {/* )} */} + {/* */}
); -} \ No newline at end of file +} diff --git a/src/components/StreamWidgets.tsx b/src/components/StreamWidgets.tsx deleted file mode 100644 index f678913c..00000000 --- a/src/components/StreamWidgets.tsx +++ /dev/null @@ -1,73 +0,0 @@ -// StreamWidget.tsx -import React, { useEffect, useRef } from "react"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { validateRequiredProps } from "../helpers/validate"; - -export interface StreamWidgetProps { - client: any; - nodeId: string; - streamId: string; - streamUrl: string; -} - -export const StreamWidget: React.FC = ({ - client, - nodeId, - streamId, - streamUrl, -}) => { - validateRequiredProps("StreamWidget", { client, nodeId, streamId, streamUrl }, [ - "client", - "nodeId", - "streamId", - "streamUrl", - ]); - - const mountedRef = useRef(false); - - useEffect(() => { - if (!client || !nodeId || !streamId || !streamUrl) return; - mountedRef.current = true; - - const anedya = (client as any)._anedya as Anedya; - - const node = anedya.NewNode(client, nodeId); - console.log("Stream Node : ", node); - console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(node))); - - const stream = node.getStream(streamId, streamUrl); - - stream.onData((data: any) => { - if (!mountedRef.current) return; - console.log("Stream Data:", data); - }); - - stream.onError((err: any) => { - if (!mountedRef.current) return; - console.error("Stream Error:", err); - }); - - stream - .connect() - .then(() => { - if (mountedRef.current) console.log("Stream connected"); - }) - .catch((err: any) => { - console.error("Stream connect failed:", err); - }); - - return () => { - mountedRef.current = false; - stream.disconnect(); - console.log("Stream disconnected"); - }; - }, [client, nodeId, streamId, streamUrl]); - - return( - <> -

Stream

- - ); -}; - -export default StreamWidget; \ No newline at end of file diff --git a/src/components/chartTheme.tsx b/src/components/chartTheme.tsx deleted file mode 100644 index a50a4ce8..00000000 --- a/src/components/chartTheme.tsx +++ /dev/null @@ -1,240 +0,0 @@ -import type { ChartDataPoint } from "./ChartWidget"; - -/* ============================================================ - * ChartColors - * ------------------------------------------------------------ - * Every color/visual token the chart actually renders with. - * This is intentionally a flat object of *required* fields so - * that `themes.light` / `themes.dark` are guaranteed complete β€” - * no risk of an undefined color slipping through at render time. - * ============================================================ */ -export interface ChartColors { - strokeColor: string; - strokeWidth: number; - gradientColors: [string, string]; - dotRadius: number; - axisColor: string; - tickColor: string; - backgroundColor: string; - borderColor: string; - titleColor: string; - /** Font size (px) for axis tick labels. Exposed so responsiveStyles can shrink it on small screens. */ - tickFontSize: number; - /** Font size (px) for the chart title. Exposed so responsiveStyles can shrink it on small screens. */ - titleFontSize: number; - - barColor?: string; - barHoverColor?: string; - barRadius?: number; - tooltipBg?: string; - tooltipColor?: string; -} - -/* ============================================================ - * ChartStyleSet - * ------------------------------------------------------------ - * This is the shape every styling entry point accepts: - * - the `styles` prop (static or a function of widget state) - * - the return value of `onStyleChange` - * - each `style` inside a `defineStyleRules` rule - * - * `chart` is `Partial` because callers should be - * able to override just one or two tokens (e.g. only strokeColor - * when a threshold is crossed) without having to restate every - * other color. - * ============================================================ */ -export interface ChartStyleSet { - container?: React.CSSProperties; - title?: React.CSSProperties; - chart?: Partial; -} - -/* ============================================================ - * Theme presets - * ------------------------------------------------------------ - * These are the *base layer* of styling β€” applied before the - * user's `styles` prop and before any `onStyleChange` result. - * Add more presets here (e.g. "minimal") as needed; just make - * sure they satisfy ChartColors fully. - * ============================================================ */ -export const lightTheme: ChartColors = { - strokeColor: "#1e88e5", - strokeWidth: 2, - gradientColors: ["#1e88e5", "#90caf9"], - dotRadius: 3.5, - axisColor: "#cbd5e1", - tickColor: "#64748b", - backgroundColor: "#f8fafc", - borderColor: "#e2e8f0", - titleColor: "#0f172a", - tickFontSize: 10, - titleFontSize: 16, - - barColor: "#1e88e5", - barHoverColor: "#1565c0", - barRadius: 3, - tooltipBg: "#0f172a", - tooltipColor: "#ffffff", -}; - -export const darkTheme: ChartColors = { - strokeColor: "#60a5fa", - strokeWidth: 2, - gradientColors: ["#60a5fa", "#1e3a8a"], - dotRadius: 3.5, - axisColor: "#334155", - tickColor: "#94a3b8", - backgroundColor: "#0f172a", - borderColor: "#1e293b", - titleColor: "#f1f5f9", - tickFontSize: 10, - titleFontSize: 16, - - barColor: "#60a5fa", - barHoverColor: "#3b82f6", - barRadius: 3, - tooltipBg: "#1e293b", - tooltipColor: "#f1f5f9", -}; - -export const themes = { - light: lightTheme, - dark: darkTheme, -} as const; - -export type ThemeName = keyof typeof themes; - -/** Default theme for every ChartWidget instance unless overridden via the `theme` prop. */ -export const DEFAULT_THEME: ThemeName = "light"; - -/* ============================================================ - * mergeStyleSets - * ------------------------------------------------------------ - * Combines any number of ChartStyleSet objects, left to right, - * where later sets win. Each of container/title/chart is merged - * independently (shallow per-key), so passing only - * `{ chart: { strokeColor: "red" } }` never wipes out the other - * chart tokens that came from an earlier layer (e.g. the theme). - * - * Overall precedence used by ChartWidget (lowest to highest): - * 1. theme preset (light/dark) - * 2. `styles` prop (static object or function of widget state) - * 3. `onStyleChange` result (re-evaluated whenever data changes) - * ============================================================ */ -export function mergeStyleSets( - ...sets: (ChartStyleSet | undefined | null)[] -): ChartStyleSet { - const result: ChartStyleSet = {}; - for (const set of sets) { - if (!set) continue; - result.container = { ...result.container, ...set.container }; - result.title = { ...result.title, ...set.title }; - result.chart = { ...result.chart, ...set.chart }; - } - return result; -} - -/* ============================================================ - * Responsive breakpoints - * ------------------------------------------------------------ - * These are CONTAINER-width breakpoints (measured via - * ResizeObserver on the widget's own wrapper), not viewport/ - * window breakpoints β€” matching CSS container-query semantics - * rather than media-query semantics. That's the right behavior - * for an embeddable widget: it should adapt to the box it's - * placed in (a sidebar, a dashboard tile, a modal), not to the - * size of the browser window, which may be much larger than the - * space actually given to the widget. - * - * Thresholds mirror Tailwind's default breakpoints so the mental - * model transfers directly for anyone used to Tailwind's - * sm:/md:/lg:/xl: prefixes. - * ============================================================ */ -export type Breakpoint = "sm" | "md" | "lg" | "xl"; - -export const BREAKPOINTS: Record = { - sm: 640, - md: 768, - lg: 1024, - xl: 1280, -}; - -/** - * Responsive style map. `base` always applies; each named - * breakpoint applies *in addition*, once the container's - * measured width is >= that breakpoint's threshold β€” mobile - * first, same cascade model as Tailwind's responsive prefixes. - * - * This is a SEPARATE prop from `styles` on purpose: `styles` - * (or a static object) is unconditional fixed styling that - * applies identically at every screen size, while - * `responsiveStyles` is only ever consulted per-breakpoint. - * Passing one doesn't affect how the other behaves. - */ -export type ResponsiveStyleSet = Partial>; - -/** - * Resolves a ResponsiveStyleSet down to a single flat - * ChartStyleSet for the widget's current measured container - * width. Layers are merged in ascending breakpoint order so - * larger breakpoints override smaller ones on overlapping keys, - * exactly like cascading CSS media queries. - */ -export function resolveResponsiveStyle( - responsiveStyles: ResponsiveStyleSet | undefined, - containerWidth: number -): ChartStyleSet { - if (!responsiveStyles) return {}; - - const layers: ChartStyleSet[] = []; - if (responsiveStyles.base) layers.push(responsiveStyles.base); - - (Object.keys(BREAKPOINTS) as Breakpoint[]) - .sort((a, b) => BREAKPOINTS[a] - BREAKPOINTS[b]) - .forEach((bp) => { - if (containerWidth >= BREAKPOINTS[bp] && responsiveStyles[bp]) { - layers.push(responsiveStyles[bp]!); - } - }); - - return mergeStyleSets(...layers); -} - -/* ============================================================ - * StyleRule / defineStyleRules - * ------------------------------------------------------------ - * Sugar for the common "if value crosses some threshold, change - * the styling" pattern, without writing a raw onStyleChange - * callback by hand every time. - * - * `when` is evaluated against the *latest* data point (most - * recent value) plus the full data array, in case a rule needs - * more context (e.g. comparing against an average). - * - * If multiple rules match, their styles are merged in array - * order (later matching rules win on overlapping keys) β€” this - * lets you stack rules like "base warning color" + "critical - * override" instead of only ever applying one. - * - * Usage: - * onStyleChange={defineStyleRules([ - * { when: (d) => d.value > 80, style: { chart: { strokeColor: "#dc2626" } } }, - * { when: (d) => d.value < 20, style: { chart: { strokeColor: "#2563eb" } } }, - * ])} - * ============================================================ */ -export interface StyleRule { - when: (latest: ChartDataPoint, allData: ChartDataPoint[]) => boolean; - style: ChartStyleSet; -} - -export function defineStyleRules( - rules: StyleRule[] -): (data: ChartDataPoint[]) => ChartStyleSet { - return (data: ChartDataPoint[]) => { - const latest = data[data.length - 1]; - if (!latest) return {}; - - const matched = rules.filter((rule) => rule.when(latest, data)); - return mergeStyleSets(...matched.map((rule) => rule.style)); - }; -} diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index e26b5c4f..ba0fbe3f 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -2,7 +2,7 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "../../../dist/styles.css" +import "../../../dist/styles.css"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = @@ -32,224 +32,10 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( - //
- // {/* ============================================================ - // * 1. Default appearance β€” no theme, no styles, no - // * formatting props. Every fallback in the widget in one place. - // * ============================================================ */} - // - - // {/* ============================================================ - // * 2. theme β€” a reusable, shareable WidgetTheme object. Same - // * effect across every widget instance that uses it. - // * ============================================================ */} - // - - // {/* Built-in preset names also work directly: */} - // - - // {/* ============================================================ - // * 3. styles vs className β€” THE distinction to understand: - // * - // * - `styles` (plural, an OBJECT): per-SLOT overrides. - // * Keys are "container" | "title" | "value" | "unit" | "label" - // * β€” lets you reach INSIDE the widget and style individual - // * pieces independently. - // * - // * - `className` (singular, a STRING): the ordinary React - // * convention β€” one class applied ONLY to the widget's - // * outermost container element, same as you'd pass to any - // * other component. It's merged (via twMerge) with whatever - // * styles.container already resolved to, not a - // * replacement for it. - // * - // * This example uses BOTH at once so the difference is visible: - // * className adds a shadow to the outer box, styles.value/ - // * styles.title style two INNER pieces independently. - // * ============================================================ */} - // - - // {/* ============================================================ - // * 4. Plain CSS classes β€” classNames works with ANY class source, - // * not just Tailwind. These reference plain hand-written CSS - // * classes (e.g. defined in a .css file this app already imports). - // * ============================================================ */} - // - - // {/* ============================================================ - // * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` - // * work exactly as they do anywhere else in your app, because - // * classNames just forwards whatever string you write straight - // * to `className`. This widget does NOT have its own custom - // * breakpoint system β€” these prefixes are compiled by YOUR - // * project's Tailwind config and respond to the BROWSER VIEWPORT, - // * same as native Tailwind everywhere else. If your own - // * tailwind.config.js customizes `theme.screens`, these prefixes - // * automatically follow that customization too β€” nothing to - // * configure on the widget's side. - // * ============================================================ */} - // - - // {/* ============================================================ - // * 3. Segmented variant β€” colored ranges (risk zones), with - // * needle enabled to point at the current value (like your - // * ChartExpo reference image). - // * ============================================================ */} - // `${v.toFixed(2)} % RH`} - // labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - // /> - - // {/* ============================================================ - // * 7. onStyleChange β€” conditional class overrides driven by the - // * RAW fetched data ({ value, timestamp }), always applied on top - // * of everything else (theme, classNames, className). - // * ============================================================ */} - // { - // if (!data) return; - - // if (data.value > 80) { - // return { - // title: "High Humidity", - // theme: "dark", - // classNames: { - // value: "text-red-500", - // }, - // }; - // } - - // return { - // title: "Humidity", - // theme: "light", - // }; - // }} - // /> - - // {/* ============================================================ - // * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, - // * applied as inline styles on the container, independent of the - // * whole classNames/theme system. - // * ============================================================ */} - // - - // { - // "Hello"; - // }, - // }} - // labels={{ - // show: true, - // position: "outside", - // }} - // scale={{ - // minLabel: "Minimum", - // maxLabel: "Maximum", - // }} - // ticks={{ - // show: true, - // count: 10, - // position: "outside", - // length: 10, - // labels: true, - // }} - // animation={{ - // duration: 5000, - // easing: "easeElasticOut", - // }} - // tooltip={{ - // show: false, - // }} - // classNames={{ - // title: "text-white", - // tickLabel: "text-white text-lg", - // label: "text-white", - // value: "text-white", - // }} - // /> - //
+
- {/* */} - + + + + + + style={{ + backgroundColor: "#1e1e2f", + borderRadius: "16px", + padding: "10px", + }} + // 'styles' affects specific internal SVG/HTML slots via Tailwind classes + styles={{ + container: "border border-gray-700", // merges with outer wrapper + title: "text-purple-400 text-xs uppercase tracking-wider", + value: "text-white text-2xl font-mono", + unit: "text-gray-400 text-sm", + label: "text-gray-500 text-[10px]", + bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients + needle: "stroke-pink-400 stroke-2", + needleCap: "fill-pink-400", + }} + /> + + + + + + + + {/* // 1. Show a custom static text */} + "Last reading"} // Always shows "Last reading" + /> + + {/* // 2. Format the timestamp exactly how you want */} + + `Updated at ${new Date(timestamp).toLocaleString("en-US", { + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + })}` + } + // Output: "Updated at 02:30:45 PM" + /> + + {/* // 3. Show relative time with custom wording */} + { + const diff = Math.floor((Date.now() - timestamp) / 60000); + if (diff < 1) return "Just now"; + if (diff < 60) return `${diff} min ago`; + return `${Math.floor(diff / 60)} hours ago`; + }} + /> + + {/* // 4. Hide the label entirely (return null or empty string) */} + null} // No label shown + />
); } From f235dc9b464639e9238c36f648bce72d57c57d9f Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Fri, 24 Jul 2026 17:58:50 +0530 Subject: [PATCH 38/66] added card --- src/components/CardWidget.tsx | 6 +- test/my-app/src/App.jsx | 136 ++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 43556543..a149e047 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -234,8 +234,8 @@ export function CardWidget({ const resolveSlot = (slot: CardSlot) => twMerge( CARD_DEFAULT_CLASSES[slot], - resolvedTheme.styles[slot], - resolvedProps.styles[slot], + resolvedTheme.styles?.[slot], + resolvedProps.styles?.[slot], ); const { displayValue, displayUnit } = useMemo(() => { @@ -360,4 +360,4 @@ export function CardWidget({
); -} +} \ No newline at end of file diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index ba0fbe3f..eb4a090b 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -4,6 +4,7 @@ import { CardWidget } from "../../../src"; import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; import "../../../dist/styles.css"; +import { relativeTime } from "../../../src/helpers/formatters"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; const token = "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; @@ -28,6 +29,7 @@ const emeraldTheme = { }, }; + const commonProps = { node, variable: "humidity" }; export default function App() { @@ -36,6 +38,140 @@ export default function App() {
+ + `Last synced ${relativeTime(ts)}`} + + /> + + + {/* ============================================================ + * 2. theme β€” a reusable, shareable WidgetTheme object. Same + * effect across every widget instance that uses it. + * ============================================================ */} + + + {/* Built-in preset names also work directly: */} + + + {/* ============================================================ + * 3. styles vs className β€” THE distinction to understand: + * + * - `styles` (plural, an OBJECT): per-SLOT overrides. + * Keys are "container" | "title" | "value" | "unit" | "label" + * β€” lets you reach INSIDE the widget and style individual + * pieces independently. + * + * - `className` (singular, a STRING): the ordinary React + * convention β€” one class applied ONLY to the widget's + * outermost container element, same as you'd pass to any + * other component. It's merged (via twMerge) with whatever + * styles.container already resolved to, not a + * replacement for it. + * + * This example uses BOTH at once so the difference is visible: + * className adds a shadow to the outer box, styles.value/ + * styles.title style two INNER pieces independently. + * ============================================================ */} + + + {/* ============================================================ + * 4. Plain CSS classes β€” styles works with ANY class source, + * not just Tailwind. These reference plain hand-written CSS + * classes (e.g. defined in a .css file this app already imports). + * ============================================================ */} + {/* */} + + {/* ============================================================ + * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` + * work exactly as they do anywhere else in your app, because + * styles just forwards whatever string you write straight + * to `className`. This widget does NOT have its own custom + * breakpoint system β€” these prefixes are compiled by YOUR + * project's Tailwind config and respond to the BROWSER VIEWPORT, + * same as native Tailwind everywhere else. If your own + * tailwind.config.js customizes `theme.screens`, these prefixes + * automatically follow that customization too β€” nothing to + * configure on the widget's side. + * ============================================================ */} + {/* */} + + {/* ============================================================ + * 6. formatValue / labelText β€” simple formatting hooks, distinct + * from styling. formatValue controls the displayed number's + * text; labelText controls the caption under it. + * ============================================================ */} + {/* `${v.toFixed(2)} % RH`} + labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} + + /> */} + + {/* ============================================================ + * 7. onStyleChange β€” conditional class overrides driven by the + * RAW fetched data ({ value, timestamp }), always applied on top + * of everything else (theme, styles, className). + * ============================================================ */} + {/* { + if (!data) return; + + if (data.value > 80) { + return { + title: "High Humidity", + theme: "dark", + styles: { + value: "text-red-500" + } + }; + } + + return { + title: "Humidity", + theme: "light" + }; + }} + + /> */} + + {/* ============================================================ + * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, + * applied as inline styles on the container, independent of the + * whole styles/theme system. + * ============================================================ */} + {/* */} + + {/* Date: Fri, 24 Jul 2026 20:43:57 +0530 Subject: [PATCH 39/66] added gauge widget examples --- .../GaugeChart/GaugeChartWidget.tsx | 37 +- src/themes/gaugeTheme.ts | 3 + src/types/gauge.ts | 5 +- test/my-app/src/App.jsx | 394 ++++++++--------- test/my-app/src/Test.tsx | 403 ++++++++++++++++++ 5 files changed, 618 insertions(+), 224 deletions(-) create mode 100644 test/my-app/src/Test.tsx diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index c1c42315..e9cc1337 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -1315,6 +1315,14 @@ export function GaugeWidget({ length: resolvedProps.needle?.length ?? "medium", width: resolvedProps.needle?.width ?? 4, color: resolvedProps.needle?.color ?? "", + needleColor: + resolvedProps.needle?.needleColor ?? + resolvedProps.needle?.color ?? + "currentColor", + capColor: + resolvedProps.needle?.capColor ?? + resolvedProps.needle?.color ?? + "currentColor", capRadius: resolvedProps.needle?.capRadius ?? 6, animation: resolvedProps.needle?.animation ?? true, }; @@ -1413,7 +1421,7 @@ export function GaugeWidget({ const pad = 8; // const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; - const textReserve = 0; + const textReserve = 0; const availW = boxWidth - pad * 2; const availH = boxHeight * (1 - textReserve) - pad * 2; @@ -1545,11 +1553,14 @@ export function GaugeWidget({ shape.tag as any, "circle.anedya-gauge-needle-cap" ); + needleEl.attr("class", resolveSlot("needle")); + needleEl - .attr("class", resolveSlot("needle")) - .attr("fill", resolvedNeedle.color || "currentColor") - .attr("stroke", resolvedNeedle.color || "currentColor") - .attr("opacity", loading ? 0.4 : 1); + .attr("class", resolveSlot("needle")) + .attr("fill", resolvedNeedle.needleColor) + .attr("stroke", resolvedNeedle.needleColor) + .attr("opacity", loading ? 0.4 : 1); + Object.entries(shape.attrs).forEach(([k, v]) => needleEl.attr( k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), @@ -1569,9 +1580,9 @@ export function GaugeWidget({ ); } cap - .attr("r", resolvedNeedle.capRadius) - .attr("fill", resolvedNeedle.color || "currentColor") - .attr("opacity", loading ? 0.4 : 1); + .attr("r", resolvedNeedle.capRadius) + .attr("fill", resolvedNeedle.capColor) // ← use capColor + .attr("opacity", loading ? 0.4 : 1); const targetDeg = valueAngle / DEG2RAD; if (resolvedNeedle.animation) { @@ -1769,7 +1780,7 @@ export function GaugeWidget({ ) : ( <> {/* Value + Unit */} - {/* */} - {/* Label (timestamp) */} - {/* {displayLabel && ( + {/* Label (timestamp) */} + {/* {displayLabel && ( )} */} - {/* */} - {/* )} */} + {/* */} + {/* )} */} {/* */}
); diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index efffe9dd..7f317a1d 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -73,6 +73,7 @@ export const GAUGE_DEFAULT_CLASSES: Record = { container: "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", title: "text-[length:var(--anedya-gauge-title-size)] font-medium", + unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", track: "", bar: "", needle: "", @@ -85,6 +86,7 @@ export const gaugeLightTheme: WidgetTheme = { styles: { container: "", title: "text-slate-500", + unit: "text-slate-500", track: "text-slate-200", // read via `currentColor` on the track path bar: "text-indigo-500", needle: "text-slate-700", @@ -98,6 +100,7 @@ export const gaugeDarkTheme: WidgetTheme = { styles: { container: "", title: "text-slate-400", + unit: "text-slate-400", track: "text-slate-700", bar: "text-indigo-400", needle: "text-slate-200", diff --git a/src/types/gauge.ts b/src/types/gauge.ts index c5ee4a4a..7768034d 100644 --- a/src/types/gauge.ts +++ b/src/types/gauge.ts @@ -115,6 +115,7 @@ export type GaugeSlot = | "container" | "title" + | "unit" | "track" | "bar" | "needle" @@ -148,7 +149,9 @@ export interface GaugeNeedleConfig { /** Preset or px. Relative to computed radius when a preset is used. */ length?: "short" | "medium" | "full" | number; width?: number; - color?: string; + color?: string; + needleColor?: string; + capColor?: string; capRadius?: number; animation?: boolean; } diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index eb4a090b..8f19d6d6 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -29,31 +29,45 @@ const emeraldTheme = { }, }; - const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
- - `Last synced ${relativeTime(ts)}`} - - /> - - + `Last synced ${relativeTime(ts)}`} + /> {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same * effect across every widget instance that uses it. * ============================================================ */} - - + {/* Built-in preset names also work directly: */} - - + {/* ============================================================ * 3. styles vs className β€” THE distinction to understand: * @@ -83,9 +97,7 @@ export default function App() { value: "text-red-500 text-5xl", // <- targets the INNER "value" slot specifically title: "uppercase tracking-wider text-yellow-500", // <- targets the INNER "title" slot specifically }} - /> - {/* ============================================================ * 4. Plain CSS classes β€” styles works with ANY class source, * not just Tailwind. These reference plain hand-written CSS @@ -98,7 +110,6 @@ export default function App() { decimalPlaces={1} styles={{ container: "my-card", value: "my-card-value" }} /> */} - {/* ============================================================ * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` * work exactly as they do anywhere else in your app, because @@ -118,7 +129,6 @@ export default function App() { decimalPlaces={1} styles={{ value: "text-2xl sm:text-3xl md:text-4xl lg:text-5xl" }} /> */} - {/* ============================================================ * 6. formatValue / labelText β€” simple formatting hooks, distinct * from styling. formatValue controls the displayed number's @@ -131,7 +141,6 @@ export default function App() { labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} /> */} - {/* ============================================================ * 7. onStyleChange β€” conditional class overrides driven by the * RAW fetched data ({ value, timestamp }), always applied on top @@ -163,233 +172,198 @@ export default function App() { }} /> */} - {/* ============================================================ * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, * applied as inline styles on the container, independent of the * whole styles/theme system. * ============================================================ */} {/* */} - - - {/* { - // "Hello"; - // }, - // }} - // labels={{ - // show: true, - // position: "outside", - // }} - // scale={{ - // minLabel: "Hello", - // maxLabel: "World", - // }} - // ticks={{ - // show: true, - // count: 10, - // position: "outside", - // length: 10, - // labels: true, - // }} - animation={{ - duration: 4000, - easing: "easeElasticOut", // easeCubicOut, easeElasticOut - }} - // tooltip={{ - // show:false, - // }} - // classNames={{ - // title: "text-white", - // tickLabel: "text-white text-lg", - // label: "text-red", - // value: "text-white", - // }} - theme="dark" - /> */} - + + - - - style={{ - backgroundColor: "#1e1e2f", - borderRadius: "16px", - padding: "10px", + value={55} + title="No Value Label" + valueLabel={{ show: false }} + /> + + + + + + - - + - +
+ +
+ - - {/* // 1. Show a custom static text */} "Last reading"} // Always shows "Last reading" + value={66} + title="Clickable" + onClick={(v) => alert(`Clicked ${v}`)} /> - - {/* // 2. Format the timestamp exactly how you want */} + {/* */} + {/* */} - `Updated at ${new Date(timestamp).toLocaleString("en-US", { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - })}` - } - // Output: "Updated at 02:30:45 PM" + {...commonProps} + // value={42} + timestamp={Date.now() - 3600000} // 1 hour ago + title="Relative Time" + labelFormat="relative" /> - - {/* // 3. Show relative time with custom wording */} { - const diff = Math.floor((Date.now() - timestamp) / 60000); - if (diff < 1) return "Just now"; - if (diff < 60) return `${diff} min ago`; - return `${Math.floor(diff / 60)} hours ago`; - }} + {...commonProps} + // value={42} + timestamp={Date.now()} + title="Custom Label" + labelText={(ts) => `Last seen: ${new Date(ts).toLocaleTimeString()}`} + /> + `⭐ ${Math.round(v)}%`} // your own text + unit="" // hide unit + labelText={(ts) => `recorded ${new Date(ts).toLocaleString()}`} + timestamp={Date.now() - 86400000} // 1 day ago + onClick={(v) => console.log("Clicked", v)} + onValueChange={(v) => console.log("Changed to", v)} /> - - {/* // 4. Hide the label entirely (return null or empty string) */} null} // No label shown + {...commonProps} + // value={78} + unit="(*)" + title="Dynamic Gauge" + min={0} + max={100} + // className="border-2 border-blue-200 hover:border-blue-400 transition-colors" + onDataChange={(data) => { + if (!data) return {}; + const { value } = data; + if (value > 80) return { title: "πŸ”΄ Critical", color: "#dc2626" }; + if (value > 50) return { title: "🟑 Warning", color: "#f59e0b" }; + return { title: "🟒 Normal", color: "#10b981" }; + }} + onValueChange={(v) => console.log("Live value:", v)} + // styles={{ + // container:"", + // // "bg-slate-50 dark:bg-slate-800 rounded-2xl shadow-lg border", + // title: "text-base font-bold tracking-wide", + // value: "text-[100px]", + // unit: "text-[200px] opacity-75", + // label: "text-xs italic text-gray-500", + // }} /> + {" "}
); } diff --git a/test/my-app/src/Test.tsx b/test/my-app/src/Test.tsx new file mode 100644 index 00000000..eb4a090b --- /dev/null +++ b/test/my-app/src/Test.tsx @@ -0,0 +1,403 @@ +import React from "react"; +import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; +import { CardWidget } from "../../../src"; +import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; +import "../../../dist/styles.css"; + +import { relativeTime } from "../../../src/helpers/formatters"; +const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; +const token = + "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; +const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; + +const anedya = new Anedya(); +const config = anedya.newConfig(tokenId, token); +const client = anedya.newClient(config); +const node = anedya.newNode(client, nodeId); + +/** + * A reusable theme, shareable across every CardWidget instance in your + * app. Only specify the slots you actually want to change from the + * built-in default β€” anything omitted falls back to lightTheme/darkTheme. + */ +const emeraldTheme = { + classNames: { + container: "bg-emerald-50 border-emerald-200", + title: "text-emerald-700", + value: "text-emerald-900", + label: "text-emerald-500", + }, +}; + + +const commonProps = { node, variable: "humidity" }; + +export default function App() { + return ( + +
+ + `Last synced ${relativeTime(ts)}`} + + /> + + + {/* ============================================================ + * 2. theme β€” a reusable, shareable WidgetTheme object. Same + * effect across every widget instance that uses it. + * ============================================================ */} + + + {/* Built-in preset names also work directly: */} + + + {/* ============================================================ + * 3. styles vs className β€” THE distinction to understand: + * + * - `styles` (plural, an OBJECT): per-SLOT overrides. + * Keys are "container" | "title" | "value" | "unit" | "label" + * β€” lets you reach INSIDE the widget and style individual + * pieces independently. + * + * - `className` (singular, a STRING): the ordinary React + * convention β€” one class applied ONLY to the widget's + * outermost container element, same as you'd pass to any + * other component. It's merged (via twMerge) with whatever + * styles.container already resolved to, not a + * replacement for it. + * + * This example uses BOTH at once so the difference is visible: + * className adds a shadow to the outer box, styles.value/ + * styles.title style two INNER pieces independently. + * ============================================================ */} + + + {/* ============================================================ + * 4. Plain CSS classes β€” styles works with ANY class source, + * not just Tailwind. These reference plain hand-written CSS + * classes (e.g. defined in a .css file this app already imports). + * ============================================================ */} + {/* */} + + {/* ============================================================ + * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` + * work exactly as they do anywhere else in your app, because + * styles just forwards whatever string you write straight + * to `className`. This widget does NOT have its own custom + * breakpoint system β€” these prefixes are compiled by YOUR + * project's Tailwind config and respond to the BROWSER VIEWPORT, + * same as native Tailwind everywhere else. If your own + * tailwind.config.js customizes `theme.screens`, these prefixes + * automatically follow that customization too β€” nothing to + * configure on the widget's side. + * ============================================================ */} + {/* */} + + {/* ============================================================ + * 6. formatValue / labelText β€” simple formatting hooks, distinct + * from styling. formatValue controls the displayed number's + * text; labelText controls the caption under it. + * ============================================================ */} + {/* `${v.toFixed(2)} % RH`} + labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} + + /> */} + + {/* ============================================================ + * 7. onStyleChange β€” conditional class overrides driven by the + * RAW fetched data ({ value, timestamp }), always applied on top + * of everything else (theme, styles, className). + * ============================================================ */} + {/* { + if (!data) return; + + if (data.value > 80) { + return { + title: "High Humidity", + theme: "dark", + styles: { + value: "text-red-500" + } + }; + } + + return { + title: "Humidity", + theme: "light" + }; + }} + + /> */} + + {/* ============================================================ + * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, + * applied as inline styles on the container, independent of the + * whole styles/theme system. + * ============================================================ */} + {/* */} + + + {/* { + // "Hello"; + // }, + // }} + // labels={{ + // show: true, + // position: "outside", + // }} + // scale={{ + // minLabel: "Hello", + // maxLabel: "World", + // }} + // ticks={{ + // show: true, + // count: 10, + // position: "outside", + // length: 10, + // labels: true, + // }} + animation={{ + duration: 4000, + easing: "easeElasticOut", // easeCubicOut, easeElasticOut + }} + // tooltip={{ + // show:false, + // }} + // classNames={{ + // title: "text-white", + // tickLabel: "text-white text-lg", + // label: "text-red", + // value: "text-white", + // }} + theme="dark" + /> */} + + + + + + + style={{ + backgroundColor: "#1e1e2f", + borderRadius: "16px", + padding: "10px", + }} + // 'styles' affects specific internal SVG/HTML slots via Tailwind classes + styles={{ + container: "border border-gray-700", // merges with outer wrapper + title: "text-purple-400 text-xs uppercase tracking-wider", + value: "text-white text-2xl font-mono", + unit: "text-gray-400 text-sm", + label: "text-gray-500 text-[10px]", + bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients + needle: "stroke-pink-400 stroke-2", + needleCap: "fill-pink-400", + }} + /> + + + + + + + + {/* // 1. Show a custom static text */} + "Last reading"} // Always shows "Last reading" + /> + + {/* // 2. Format the timestamp exactly how you want */} + + `Updated at ${new Date(timestamp).toLocaleString("en-US", { + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + })}` + } + // Output: "Updated at 02:30:45 PM" + /> + + {/* // 3. Show relative time with custom wording */} + { + const diff = Math.floor((Date.now() - timestamp) / 60000); + if (diff < 1) return "Just now"; + if (diff < 60) return `${diff} min ago`; + return `${Math.floor(diff / 60)} hours ago`; + }} + /> + + {/* // 4. Hide the label entirely (return null or empty string) */} + null} // No label shown + /> +
+ ); +} + +{ + /* +//create react app +//link public-widget-sdk +//npm run dev +//send this file tp yash to copy paste */ +} From cac678b70fb308a367e4e68febcfddeebaf35436 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Sat, 25 Jul 2026 11:32:57 +0530 Subject: [PATCH 40/66] change export --- package.json | 1 + test/my-app/package-lock.json | 29 ++++++++++++++++++++++++++++- test/my-app/src/App.jsx | 15 +++++++++------ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 7fcc64e8..23374949 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "dev": "npm run clean && tsdown --watch", "typecheck": "tsc --noEmit" }, + "repository": { "type": "git", diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index 1e4becda..b8f102c6 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -30,7 +30,34 @@ "vite": "^8.0.1" } }, - "../..": {}, + "../..": { + "name": "public-widget-sdk", + "version": "5.5.0", + "license": "ISC", + "dependencies": { + "@anedyasystems/anedya-frontend-sdk": "^0.1.1", + "@types/d3": "^7.4.3", + "clsx": "^2.1.1", + "d3": "^7.9.0", + "tailwind-merge": "^3.6.0" + }, + "devDependencies": { + "@base-ui/react": "^1.6.0", + "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.3.2", + "tsdown": "^0.22.13", + "typescript": "^5.7.3" + }, + "peerDependencies": { + "@base-ui/react": "^1.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 8f19d6d6..f4b5ff9d 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -2,7 +2,7 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; import { CardWidget } from "../../../src"; import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "../../../dist/styles.css"; +import "public-widget-sdk/styles.css"; import { relativeTime } from "../../../src/helpers/formatters"; const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; @@ -179,13 +179,15 @@ export default function App() { * ============================================================ */} {/* */} + + + + + `recorded ${new Date(ts).toLocaleString()}`} timestamp={Date.now() - 86400000} // 1 day ago onClick={(v) => console.log("Clicked", v)} - onValueChange={(v) => console.log("Changed to", v)} /> 50) return { title: "🟑 Warning", color: "#f59e0b" }; return { title: "🟒 Normal", color: "#10b981" }; }} - onValueChange={(v) => console.log("Live value:", v)} // styles={{ // container:"", // // "bg-slate-50 dark:bg-slate-800 rounded-2xl shadow-lg border", @@ -362,7 +365,7 @@ export default function App() { /> {" "}
); From f18f0d166df12f35f030c1f68d49da5226c1d61b Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Sat, 25 Jul 2026 16:37:16 +0530 Subject: [PATCH 41/66] Add ticks --- .../GaugeChart/GaugeChartWidget.tsx | 1484 ++++---------- src/styles/base.css | 42 +- src/themes/gaugeTheme.ts | 82 +- src/types/gauge.ts | 177 +- test/my-app/src/App.jsx | 61 +- test/my-app/src/Test.tsx | 1706 +++++++++++++---- 6 files changed, 1824 insertions(+), 1728 deletions(-) diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index e9cc1337..8277506c 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -1,932 +1,4 @@ -// import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -// import * as d3 from "d3"; -// import { twMerge } from "tailwind-merge"; -// import { AnedyaWidgetBaseProps } from "../../common"; -// import { SlotClassNames, WidgetTheme } from "../../types/root"; -// import { -// GaugeAnimationConfig, -// GaugeArcConfig, -// GaugeBarSpec, -// GaugeColor, -// GaugeLabelsConfig, -// GaugeNeedleConfig, -// GaugeNeedleLabelConfig, -// GaugeScaleConfig, -// GaugeSegment, -// GaugeSlot, -// GaugeThreshold, -// GaugeTicksConfig, -// GaugeTooltipConfig, -// GaugeTrackConfig, -// GaugeValueLabelConfig, -// GaugeVariant, -// } from "../../types/gauge"; -// import { -// DEFAULT_GAUGE_THEME, -// GAUGE_DEFAULT_CLASSES, -// gaugeDarkTheme, -// gaugeLightTheme, -// } from "../../themes/gaugeTheme"; -// import { useResizeObserver } from "../../hooks/useResizeObserver"; - -// export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { -// variant?: GaugeVariant; -// /** Used before live data arrives, or standalone in dummy-data mode. */ -// value?: number; -// min?: number; -// max?: number; -// size?: number; -// responsive?: boolean; - -// arc?: GaugeArcConfig; -// track?: GaugeTrackConfig; -// fillMode?: "progress" | "solid"; -// /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ -// color?: GaugeColor; -// bars?: GaugeBarSpec[]; - -// needle?: GaugeNeedleConfig; -// labels?: GaugeLabelsConfig; -// valueLabel?: GaugeValueLabelConfig; -// needleLabel?: GaugeNeedleLabelConfig; -// scale?: GaugeScaleConfig; -// ticks?: GaugeTicksConfig; -// segments?: GaugeSegment[]; -// thresholds?: GaugeThreshold[]; -// animation?: GaugeAnimationConfig; -// tooltip?: GaugeTooltipConfig; - -// classNames?: SlotClassNames; -// style?: React.CSSProperties; - -// onClick?: (value: number) => void; -// onHover?: (value: number | null) => void; -// onValueChange?: (value: number) => void; -// } - -// const DEG2RAD = Math.PI / 180; - -// const DEFAULT_ARC: Required> = { -// startAngle: -90, -// endAngle: 90, -// cornerRadius: 0, -// gap: 6, -// }; - -// const DEFAULT_ANIMATION: Required = { -// duration: 750, -// easing: "easeCubicOut", -// }; - -// function resolveEase(name: string) { -// return (d3 as any)[name] ?? d3.easeCubicOut; -// } - -// function needlePixelLength( -// length: GaugeNeedleConfig["length"], -// radius: number -// ) { -// if (typeof length === "number") return length; -// switch (length) { -// case "short": -// return radius * 0.55; -// case "full": -// return radius * 0.95; -// case "medium": -// default: -// return radius * 0.75; -// } -// } - -// /** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ -// function needleShape( -// type: NonNullable, -// length: number, -// width: number -// ) { -// const w = width; -// switch (type) { -// case "line": -// return { -// tag: "line", -// attrs: { -// x1: 0, -// y1: 0, -// x2: 0, -// y2: -length, -// strokeWidth: w, -// strokeLinecap: "butt", -// }, -// }; -// case "rounded": -// return { -// tag: "line", -// attrs: { -// x1: 0, -// y1: 0, -// x2: 0, -// y2: -length, -// strokeWidth: w, -// strokeLinecap: "round", -// }, -// }; -// case "triangle": { -// const half = w / 2; -// return { -// tag: "polygon", -// attrs: { -// points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ -// -length * 0.15 -// }`, -// }, -// }; -// } -// case "drop": -// default: { -// const half = w / 2; -// // Teardrop: rounded base, sharp tip. -// const d = `M ${-half} 0 -// C ${-half} ${-length * 0.35}, ${-w} ${ -// -length * 0.7 -// }, 0 ${-length} -// C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 -// A ${half} ${half} 0 1 1 ${-half} 0 Z`; -// return { tag: "path", attrs: { d } }; -// } -// } -// } - -// function isGradientColor(c?: GaugeColor): c is string[] { -// return Array.isArray(c) && c.length >= 2; -// } - -// /** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ -// function resolveFill( -// defs: d3.Selection, -// id: string, -// color: GaugeColor | undefined, -// fallback: string -// ): string { -// if (!color) return fallback; -// if (!isGradientColor(color)) return color; - -// let grad = defs.select(`#${id}`); -// if (grad.empty()) { -// grad = defs.append("linearGradient").attr("id", id); -// } -// grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); -// grad.selectAll("stop").remove(); -// color.forEach((c, i) => -// grad -// .append("stop") -// .attr("offset", `${(i / (color.length - 1)) * 100}%`) -// .attr("stop-color", c) -// ); -// return `url(#${id})`; -// } - -// /** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ -// function getArcBounds(startDeg: number, endDeg: number) { -// const lo = Math.min(startDeg, endDeg); -// const hi = Math.max(startDeg, endDeg); -// const angles = [startDeg, endDeg]; -// for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); - -// let minX = Infinity, -// maxX = -Infinity, -// minY = Infinity, -// maxY = -Infinity; -// angles.forEach((deg) => { -// const a = deg * DEG2RAD; -// const x = Math.sin(a); -// const y = -Math.cos(a); -// minX = Math.min(minX, x); -// maxX = Math.max(maxX, x); -// minY = Math.min(minY, y); -// maxY = Math.max(maxY, y); -// }); -// return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; -// } - -// export function GaugeWidget({ -// node, -// variable, -// title, -// theme, -// className, -// style, -// width, -// height, -// minWidth = 160, -// maxWidth = 480, -// minHeight = 160, -// maxHeight = 480, -// aspectRatio, - -// variant = "progress", -// value: valueProp, -// min = 0, -// max = 100, -// size, -// responsive = true, - -// arc, -// track, -// fillMode = "progress", -// color, -// bars, - -// needle, -// labels, -// valueLabel, -// needleLabel, -// scale, -// ticks, -// segments, -// thresholds, -// animation, -// tooltip, - -// classNames = {}, -// onClick, -// onHover, -// onValueChange, -// }: GaugeWidgetProps) { -// const svgRef = useRef(null); -// const tooltipRef = useRef(null); -// const prevValueRef = useRef(min); - -// const [fetchedValue, setFetchedValue] = useState(null); -// const [hoverValue, setHoverValue] = useState(null); - -// // ---- Live data fetch (mirrors CardWidget) ---- -// useEffect(() => { -// if (!node) return; -// let mounted = true; - -// node -// .getLatestData(variable) -// .then((res: any) => { -// if (!mounted) return; -// if (res?.isSuccess && res?.isDataAvailable) { -// setFetchedValue(res.data.value); -// } -// }) -// .catch(() => { -// /* fall back to `value` prop / dummy data silently */ -// }); - -// return () => { -// mounted = false; -// }; -// }, [node, variable]); - -// const rawValue = fetchedValue ?? valueProp ?? min; -// const clampedValue = Math.min(max, Math.max(min, rawValue)); - -// useEffect(() => { -// onValueChange?.(clampedValue); -// }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps - -// // ---- Responsive sizing ---- -// const { ref: wrapperRef, size: dims } = useResizeObserver( -// responsive && size == null -// ); - -// // ---- Resolved config (defaults per variant) ---- -// const resolvedArc = { ...DEFAULT_ARC, ...arc }; - -// const resolvedTrack: Required = { -// show: track?.show ?? true, -// color: track?.color ?? "", -// }; - -// const needleShownByDefault = variant === "progress" || variant === "needle"; - -// const resolvedNeedle: Required> & { -// length: NonNullable; -// } = { -// show: needle?.show ?? needleShownByDefault, -// type: needle?.type ?? "rounded", -// length: needle?.length ?? "medium", -// width: needle?.width ?? 4, -// color: needle?.color ?? "", -// capRadius: needle?.capRadius ?? 6, -// animation: needle?.animation ?? true, -// }; - -// const resolvedLabels: Required = { -// show: labels?.show ?? true, -// position: labels?.position ?? "outside", -// }; - -// const resolvedValueLabel: Required< -// Omit -// > & { formatter?: (v: number) => string } = { -// show: valueLabel?.show ?? true, -// precision: valueLabel?.precision ?? 0, -// prefix: valueLabel?.prefix ?? "", -// suffix: valueLabel?.suffix ?? "", -// formatter: valueLabel?.formatter, -// }; - -// const resolvedNeedleLabel: Required< -// Omit -// > & { formatter?: (v: number) => string } = { -// show: needleLabel?.show ?? false, -// formatter: needleLabel?.formatter, -// }; - -// const resolvedTicks: Required = { -// show: ticks?.show ?? (variant === "needle" || variant === "segmented"), -// count: ticks?.count ?? 5, -// position: ticks?.position ?? "outside", -// length: ticks?.length ?? 6, -// labels: ticks?.labels ?? true, -// }; - -// const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; - -// const resolvedTooltip: Required = { -// show: tooltip?.show ?? true, -// }; - -// // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- -// const resolvedTheme: WidgetTheme = -// theme === "dark" -// ? gaugeDarkTheme -// : theme === "light" -// ? gaugeLightTheme -// : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; - -// const resolveSlot = useCallback( -// (slot: GaugeSlot) => -// twMerge( -// GAUGE_DEFAULT_CLASSES[slot], -// resolvedTheme.styles[slot], -// classNames[slot] -// ), -// [resolvedTheme, classNames] -// ); - -// const boxWidth = size ?? width ?? (dims.width || 240); - -// const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); - -// const bounds = useMemo( -// () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), -// [resolvedArc.startAngle, resolvedArc.endAngle] -// ); - -// const pad = 8; -// // Reserve room below the arc for value/needle-label/variable text so -// // the dome never gets crowded β€” bigger reserve when the value label is on. -// const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; - -// // Ticks (and their number labels) draw *outside* the arc's own radius, -// // so the radius-fit math below must shrink the arc enough to leave -// // room for them β€” otherwise tick labels get clipped by the SVG -// // viewBox, which looked like "some ticks are hidden". -// const tickOverflow = -// resolvedTicks.show && resolvedTicks.position !== "inside" -// ? resolvedTicks.length + (resolvedTicks.labels ? 26 : 8) -// : 0; -// // Scale min/max labels also draw past the arc's radius at the two ends. -// const scaleLabelOverflow = -// resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) ? 24 : 0; -// const edgeOverflow = Math.max(tickOverflow, scaleLabelOverflow); - -// const availW = boxWidth - pad * 2 - edgeOverflow * 2; -// const availH = boxHeight * (1 - textReserve) - pad * 2 - edgeOverflow; - -// const outerRadius = -// resolvedArc.radius ?? -// Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); - -// const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); - -// // Center the arc's bounding box within the available width, anchor its top at `pad`. -// const cx = -// pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; -// const cy = pad - bounds.minY * outerRadius; - -// const angleScale = useMemo( -// () => -// d3 -// .scaleLinear() -// .domain([min, max]) -// .range([ -// resolvedArc.startAngle * DEG2RAD, -// resolvedArc.endAngle * DEG2RAD, -// ]) -// .clamp(true), -// [min, max, resolvedArc.startAngle, resolvedArc.endAngle] -// ); - -// // ---- D3 draw ---- -// useEffect(() => { -// if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; - -// const svg = d3.select(svgRef.current); -// const defs = svg.select("defs"); -// const root = svg.select("g.anedya-gauge-root"); -// root.attr("transform", `translate(${cx},${cy})`); - -// const ease = resolveEase(resolvedAnimation.easing); -// const arcGen = d3 -// .arc<{ startAngle: number; endAngle: number; r: number }>() -// .innerRadius((d) => d.r - thickness) -// .outerRadius((d) => d.r) -// .cornerRadius(resolvedArc.cornerRadius) -// .startAngle((d) => d.startAngle) -// .endAngle((d) => d.endAngle); - -// const startA = resolvedArc.startAngle * DEG2RAD; -// const endA = resolvedArc.endAngle * DEG2RAD; - -// // --- Track --- -// const trackSel = root.select( -// "path.anedya-gauge-track-path" -// ); -// if (resolvedTrack.show && variant !== "multiBar") { -// trackSel -// .attr( -// "d", -// arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! -// ) -// .attr("fill", resolvedTrack.color || "currentColor") -// .attr("opacity", 1); -// } else { -// trackSel.attr("opacity", 0); -// } - -// // --- Bar (progress / solid / segmented base) --- -// const barGroup = root.select("g.anedya-gauge-bar-group"); -// barGroup.selectAll("*").remove(); - -// if (variant === "multiBar" && bars?.length) { -// const maxBars = bars.slice(0, 10); -// maxBars.forEach((bar, i) => { -// const r = outerRadius - i * (thickness + resolvedArc.gap); -// if (resolvedTrack.show) { -// barGroup -// .append("path") -// .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) -// .attr( -// "class", -// twMerge("anedya-gauge-multibar-track", resolveSlot("track")) -// ) -// .attr("fill", resolvedTrack.color || "currentColor") -// .attr("stroke", "none"); -// } -// const valAngle = d3 -// .scaleLinear() -// .domain([min, max]) -// .range([startA, endA]) -// .clamp(true)(bar.value); - -// const barFill = resolveFill( -// defs, -// `anedya-gauge-bar-fill-${i}`, -// bar.color, -// "currentColor" -// ); - -// const path = barGroup -// .append("path") -// .attr("class", resolveSlot("bar")) -// .attr("fill", barFill) -// .attr("stroke", "none"); -// path -// .datum({ startAngle: startA, endAngle: startA, r }) -// .attr("d", arcGen as any) -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("d", function (d: any) { -// const i2 = d3.interpolate(d.endAngle, valAngle); -// return (t) => { -// d.endAngle = i2(t); -// return arcGen(d)!; -// }; -// }); -// }); -// } else if (segments?.length) { -// const scaleAngle = d3 -// .scaleLinear() -// .domain([min, max]) -// .range([startA, endA]) -// .clamp(true); -// // Half the configured gap, converted from px to radians at this radius, -// // so adjoining segments get visible separation like distinct blocks. -// const gapRad = resolvedArc.gap / 2 / outerRadius || 0; - -// const segArcGen = d3 -// .arc<{ startAngle: number; endAngle: number; r: number }>() -// .innerRadius((d) => d.r - thickness) -// .outerRadius((d) => d.r) -// .cornerRadius(resolvedArc.cornerRadius || thickness / 4) -// .startAngle((d) => d.startAngle) -// .endAngle((d) => d.endAngle); - -// segments.forEach((seg, idx) => { -// const segStart = scaleAngle(seg.from) + gapRad; -// const segEnd = scaleAngle(seg.to) - gapRad; -// if (segEnd <= segStart) return; - -// const fill = resolveFill( -// defs, -// `anedya-gauge-segment-fill-${idx}`, -// seg.color, -// "currentColor" -// ); -// barGroup -// .append("path") -// .attr("class", resolveSlot("segment")) -// .attr("fill", fill) -// .attr("stroke", "none") -// .attr( -// "d", -// segArcGen({ -// startAngle: segStart, -// endAngle: segEnd, -// r: outerRadius, -// })! -// ); -// }); -// } else { -// const valueAngle = angleScale(clampedValue); -// const barColorRaw: GaugeColor | undefined = -// color ?? -// (thresholds?.length -// ? [...thresholds] -// .sort((a, b) => a.value - b.value) -// .reduce( -// (acc, th) => (clampedValue >= th.value ? th.color : acc), -// thresholds[0].color -// ) -// : undefined); - -// const barFill = resolveFill( -// defs, -// "anedya-gauge-bar-fill", -// barColorRaw, -// "currentColor" -// ); - -// const path = barGroup -// .append("path") -// .attr("class", resolveSlot("bar")) -// .attr("fill", barFill) -// .attr("stroke", "none"); - -// const from = fillMode === "solid" ? startA : startA; -// const to = fillMode === "solid" ? endA : valueAngle; - -// path -// .datum({ -// startAngle: startA, -// endAngle: -// prevValueRef.current != null -// ? angleScale(prevValueRef.current) -// : startA, -// r: outerRadius, -// }) -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("d", function (d: any) { -// const i2 = d3.interpolate(d.endAngle, to); -// return (t) => { -// d.endAngle = i2(t); -// return arcGen({ -// startAngle: from, -// endAngle: d.endAngle, -// r: outerRadius, -// })!; -// }; -// }); -// } - -// // --- Ticks --- -// const tickGroup = root.select("g.anedya-gauge-ticks"); -// tickGroup.selectAll("*").remove(); -// if (resolvedTicks.show) { -// const count = Math.max(2, resolvedTicks.count); -// const tickR = -// resolvedTicks.position === "inside" -// ? outerRadius - thickness -// : resolvedTicks.position === "cross" -// ? outerRadius - thickness / 2 -// : outerRadius + 4; -// d3.range(count).forEach((i) => { -// const t = i / (count - 1); -// const tv = min + t * (max - min); -// const a = angleScale(tv); -// const x1 = Math.sin(a) * tickR; -// const y1 = -Math.cos(a) * tickR; -// const x2 = -// Math.sin(a) * -// (tickR + -// (resolvedTicks.position === "inside" -// ? -resolvedTicks.length -// : resolvedTicks.length)); -// const y2 = -// -Math.cos(a) * -// (tickR + -// (resolvedTicks.position === "inside" -// ? -resolvedTicks.length -// : resolvedTicks.length)); -// tickGroup -// .append("line") -// .attr("class", resolveSlot("tick")) -// .attr("stroke", "currentColor") -// .attr("x1", x1) -// .attr("y1", y1) -// .attr("x2", x2) -// .attr("y2", y2); - -// if (resolvedTicks.labels) { -// const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); -// const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); -// tickGroup -// .append("text") -// .attr("class", resolveSlot("tickLabel")) -// .attr("x", lx) -// .attr("y", ly) -// .attr("text-anchor", "middle") -// .attr("dominant-baseline", "middle") -// .text(String(Math.round(tv))); -// } -// }); -// } -// // --- Scale min/max labels (drawn at the arc's real start/end points, -// // not floated at the container's edges) --- -// const scaleLabelGroup = root.select( -// "g.anedya-gauge-scale-labels" -// ); -// scaleLabelGroup.selectAll("*").remove(); -// if (resolvedLabels.show && (scale?.minLabel || scale?.maxLabel)) { -// const labelR = -// outerRadius + -// (resolvedTicks.show ? resolvedTicks.length + 16 : 12); - -// const drawScaleLabel = (angle: number, text: string) => { -// const x = Math.sin(angle) * labelR; -// const y = -Math.cos(angle) * labelR; -// // Anchor away from the point so the label doesn't overlap the arc: -// // labels on the left side end at x, labels on the right start at x. -// const anchor = x < -2 ? "end" : x > 2 ? "start" : "middle"; -// scaleLabelGroup -// .append("text") -// .attr("class", resolveSlot("scaleLabel")) -// .attr("x", x) -// .attr("y", y) -// .attr("text-anchor", anchor) -// .attr("dominant-baseline", "middle") -// .text(text); -// }; - -// if (scale?.minLabel) drawScaleLabel(startA, scale.minLabel); -// if (scale?.maxLabel) drawScaleLabel(endA, scale.maxLabel); -// } - -// // --- Needle --- -// const needleGroup = root.select("g.anedya-gauge-needle"); -// if (resolvedNeedle.show && variant !== "multiBar") { -// const len = needlePixelLength(resolvedNeedle.length, outerRadius); -// const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); - -// needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); -// const needleEl = needleGroup.insert( -// shape.tag as any, -// "circle.anedya-gauge-needle-cap" -// ); -// needleEl -// .attr("class", resolveSlot("needle")) -// .attr("fill", resolvedNeedle.color || "currentColor") -// .attr("stroke", resolvedNeedle.color || "currentColor"); -// Object.entries(shape.attrs).forEach(([k, v]) => -// needleEl.attr( -// k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), -// v as any -// ) -// ); - -// let cap = needleGroup.select( -// "circle.anedya-gauge-needle-cap" -// ); -// if (cap.empty()) { -// cap = needleGroup -// .append("circle") -// .attr( -// "class", -// twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) -// ); -// } -// cap -// .attr("r", resolvedNeedle.capRadius) -// .attr("fill", resolvedNeedle.color || "currentColor"); - -// const targetDeg = angleScale(clampedValue) / DEG2RAD; -// if (resolvedNeedle.animation) { -// needleGroup -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("transform", function () { -// const current = needleGroup.attr("data-angle") -// ? +needleGroup.attr("data-angle")! -// : startA / DEG2RAD; -// const interp = d3.interpolate(current, targetDeg); -// return (t) => { -// const a = interp(t); -// needleGroup.attr("data-angle", String(a)); -// return `rotate(${a})`; -// }; -// }); -// } else { -// needleGroup -// .attr("transform", `rotate(${targetDeg})`) -// .attr("data-angle", String(targetDeg)); -// } -// needleGroup.attr("opacity", 1); -// } else { -// needleGroup.attr("opacity", 0); -// } - -// prevValueRef.current = clampedValue; -// }, [ -// boxWidth, -// boxHeight, -// cx, -// cy, -// outerRadius, -// thickness, -// variant, -// clampedValue, -// min, -// max, -// fillMode, -// color, -// JSON.stringify(bars), -// JSON.stringify(segments), -// JSON.stringify(thresholds), -// resolvedTrack.show, -// resolvedTrack.color, -// resolvedNeedle.show, -// resolvedNeedle.type, -// resolvedNeedle.length, -// resolvedNeedle.width, -// resolvedNeedle.color, -// resolvedNeedle.capRadius, -// resolvedNeedle.animation, -// resolvedTicks.show, -// resolvedTicks.count, -// resolvedTicks.position, -// resolvedTicks.length, -// resolvedTicks.labels, -// resolvedAnimation.duration, -// resolvedAnimation.easing, -// resolveSlot, -// resolvedLabels.show, -// scale?.minLabel, -// scale?.maxLabel, -// ]); - -// // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- -// const handlePointerMove = useCallback( -// (e: React.PointerEvent) => { -// if (!resolvedTooltip.show && !onHover) return; -// const rect = svgRef.current!.getBoundingClientRect(); -// const x = e.clientX - rect.left - cx; -// const y = e.clientY - rect.top - cy; -// const dist = Math.hypot(x, y); -// if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { -// setHoverValue(null); -// onHover?.(null); -// return; -// } -// let a = Math.atan2(x, -y); -// const hv = angleScale.invert(a); -// const clamped = Math.min(max, Math.max(min, hv)); -// setHoverValue(clamped); -// onHover?.(clamped); -// if (tooltipRef.current) { -// tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; -// tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; -// } -// }, -// [ -// cx, -// cy, -// outerRadius, -// thickness, -// angleScale, -// min, -// max, -// onHover, -// resolvedTooltip.show, -// ] -// ); - -// const handlePointerLeave = useCallback(() => { -// setHoverValue(null); -// onHover?.(null); -// }, [onHover]); - -// const handleClick = useCallback( -// () => onClick?.(clampedValue), -// [onClick, clampedValue] -// ); - -// const formattedValue = resolvedValueLabel.formatter -// ? resolvedValueLabel.formatter(clampedValue) -// : `${resolvedValueLabel.prefix}${clampedValue.toFixed( -// resolvedValueLabel.precision -// )}${resolvedValueLabel.suffix}`; - -// const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); - -// return ( -//
-// {title && {title}} - -// -// -// -// -// -// -// -// -// -// -// -// - -// {/* {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( -//
-// {scale?.minLabel} -// {scale?.maxLabel} -//
-// )} */} - -// {resolvedValueLabel.show && ( -// {formattedValue} -// )} - -// {resolvedNeedleLabel.show && needleLabelText && ( -// {needleLabelText} -// )} - -// {variable && {variable}} - -// {resolvedTooltip.show && hoverValue != null && ( -//
-// {hoverValue.toFixed(resolvedValueLabel.precision)} -//
-// )} -//
-// ); -// } +// GaugeWidget.tsx import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import * as d3 from "d3"; @@ -944,8 +16,10 @@ import { GaugeColor, GaugeNeedleConfig, GaugeSlot, + GaugeTickConfig, // NEW GaugeTrackConfig, GaugeValueLabelConfig, + GaugeEasing, } from "../../types/gauge"; import { DEFAULT_GAUGE_THEME, @@ -979,6 +53,8 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { needle?: GaugeNeedleConfig; valueLabel?: GaugeValueLabelConfig; + /** REQUIREMENT 3/4: radial min/max tick marks drawn around the arc. */ + tick?: GaugeTickConfig; animation?: GaugeAnimationConfig; // ---- Card-parity formatting props ---- @@ -994,7 +70,9 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { style?: React.CSSProperties; onClick?: (value: number) => void; - onValueChange?: (value: number) => void; + // REQUIREMENT 5: onValueChange removed β€” onDataChange already lets the + // caller override *any* prop whenever new data arrives, so a separate + // value-only callback was redundant. onDataChange?: (data: GaugeData | null) => GaugeWidgetUpdate | void; } @@ -1007,15 +85,45 @@ const DEFAULT_ARC: Required> = { }; const DEFAULT_ANIMATION: Required = { - duration: 750, - easing: "easeCubicOut", + show: true, + duration: 1000, + easing: "cubicOut", }; const DEFAULT_WIDTH = 240; const DEFAULT_HEIGHT_RATIO = 0.68; -function resolveEase(name: string) { - return (d3 as any)[name] ?? d3.easeCubicOut; +const EASE_MAP: Record = { + linear: "easeLinear", + quadIn: "easeQuadIn", + quadOut: "easeQuadOut", + quadInOut: "easeQuadInOut", + cubicIn: "easeCubicIn", + cubicOut: "easeCubicOut", + cubicInOut: "easeCubicInOut", + sinIn: "easeSinIn", + sinOut: "easeSinOut", + sinInOut: "easeSinInOut", + expIn: "easeExpIn", + expOut: "easeExpOut", + expInOut: "easeExpInOut", + circleIn: "easeCircleIn", + circleOut: "easeCircleOut", + circleInOut: "easeCircleInOut", + backIn: "easeBackIn", + backOut: "easeBackOut", + backInOut: "easeBackInOut", + elasticIn: "easeElasticIn", + elasticOut: "easeElasticOut", + elasticInOut: "easeElasticInOut", + bounceIn: "easeBounceIn", + bounceOut: "easeBounceOut", + bounceInOut: "easeBounceInOut", +}; + +function resolveEase(name: GaugeEasing) { + const d3Name = EASE_MAP[name] ?? "easeCubicOut"; + return (d3 as any)[d3Name] ?? d3.easeCubicOut; } function needlePixelLength( @@ -1154,21 +262,18 @@ export function GaugeWidget({ minHeight = 140, maxHeight = 420, aspectRatio, - value: valueProp, min = 0, max = 100, size, responsive = true, - arc, track, color, - needle, valueLabel, + tick, animation, - unit, decimalPlaces, formatValue, @@ -1176,14 +281,14 @@ export function GaugeWidget({ formatOptions, labelText, labelFormat, - styles = {}, - onClick, - onValueChange, onDataChange, + // onClick, }: GaugeWidgetProps) { const svgRef = useRef(null); - // const prevValueRef = useRef(min); + // REQUIREMENT 2: stable "now" fallback for manual/custom `value` mode, + // captured once on mount (not recomputed every render). + const manualTimestampRef = useRef(Date.now()); const [fetchedValue, setFetchedValue] = useState(null); const [timestamp, setTimestamp] = useState(null); @@ -1253,11 +358,13 @@ export function GaugeWidget({ const rawValue = fetchedValue ?? valueProp ?? min; const clampedValue = Math.min(max, Math.max(min, rawValue)); - useEffect(() => { - onValueChange?.(clampedValue); - }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps + // REQUIREMENT 5: onValueChange effect removed (see prop removal above). + + // const { ref: wrapperRef, size: dims } = useResizeObserver( + // responsive && size == null + // ); - const { ref: wrapperRef, size: dims } = useResizeObserver( + const { ref: arcWrapperRef, size: dims } = useResizeObserver( responsive && size == null ); @@ -1287,6 +394,7 @@ export function GaugeWidget({ color, needle, valueLabel, + tick, animation, unit, decimalPlaces, @@ -1336,6 +444,24 @@ export function GaugeWidget({ ...resolvedProps.animation, }; + // ---- REQUIREMENT 3/4: tick marks config ---- + // `count` = number of INTERVALS between min/max, so count=10 with the + // default min=0/max=100 draws 11 marks (0,10,20...100) β€” "10 count" per + // the ask. All sizing/color/gap knobs are user-overridable; `tick`/ + // `tickLabel` GaugeSlot entries (in `styles`) layer Tailwind classes on + // top for anything not covered by these direct props. + const resolvedTick = { + show: resolvedProps.tick?.show ?? false, + count: resolvedProps.tick?.count ?? 10, + size: resolvedProps.tick?.size ?? 6, + color: resolvedProps.tick?.color ?? "", + radiusOffset: resolvedProps.tick?.radiusOffset ?? 4, + labelGap: resolvedProps.tick?.labelGap ?? 4, + labelSize: resolvedProps.tick?.labelSize ?? 10, + labelColor: resolvedProps.tick?.labelColor ?? "", + labelFormat: resolvedProps.tick?.labelFormat, + }; + // ---- Theme + slot classes ---- const resolvedTheme: WidgetTheme = resolvedProps.theme === "dark" @@ -1354,6 +480,39 @@ export function GaugeWidget({ [resolvedTheme, resolvedProps.styles] ); + // ---- REQUIREMENT 3: tick values (min..max split into `count` even steps) ---- + const tickValues = useMemo(() => { + if (!resolvedTick.show || resolvedTick.count <= 0) return []; + const step = (resolvedProps.max - resolvedProps.min) / resolvedTick.count; + return d3 + .range(resolvedTick.count + 1) + .map((i) => resolvedProps.min + i * step); + }, [ + resolvedTick.show, + resolvedTick.count, + resolvedProps.min, + resolvedProps.max, + ]); + + // ---- REQUIREMENT 3/4: tick label formatting ---- + // Reuses the same `format` preset as the main value (if set) so tick + // labels and the big value stay consistent; falls back to a plain + // rounded number when nothing else is configured. + const formatTickLabel = useCallback( + (v: number) => { + if (resolvedTick.labelFormat) return resolvedTick.labelFormat(v); + if (resolvedProps.format) + return FORMATTERS[resolvedProps.format](v, resolvedProps.formatOptions) + .value; + return String(Math.round(v * 100) / 100); + }, + [ + resolvedTick.labelFormat, + resolvedProps.format, + resolvedProps.formatOptions, + ] + ); + // ---- Value + unit formatting (same precedence as CardWidget) ---- const { displayValue, displayUnit } = useMemo(() => { if (resolvedProps.formatValue) { @@ -1391,16 +550,26 @@ export function GaugeWidget({ resolvedProps.unit, ]); + // REQUIREMENT 2: in manual `value` mode there's no `node`, so the + // live-fetch effect never runs and `timestamp` stays null forever β€” the + // label used to just disappear in that case. Fall back to the timestamp + // captured on mount so the label still renders for custom/manual values. + const effectiveTimestamp = useMemo( + () => timestamp ?? (valueProp != null ? manualTimestampRef.current : null), + [timestamp, valueProp] + ); + // ---- Last-updated label β€” THIS is what shows the time ---- const displayLabel = useMemo(() => { - if (timestamp == null) return null; + if (effectiveTimestamp == null) return null; - if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); + if (resolvedProps.labelText) + return resolvedProps.labelText(effectiveTimestamp); const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; - return formatter(timestamp, resolvedProps.formatOptions?.locale); + return formatter(effectiveTimestamp, resolvedProps.formatOptions?.locale); }, [ - timestamp, + effectiveTimestamp, resolvedProps.labelText, resolvedProps.labelFormat, resolvedProps.formatOptions?.locale, @@ -1425,9 +594,24 @@ export function GaugeWidget({ const availW = boxWidth - pad * 2; const availH = boxHeight * (1 - textReserve) - pad * 2; + // REQUIREMENT 3: reserve room for the tick ring (line + gaps + label) + // so ticks never get clipped by the SVG viewBox. Rather than growing the + // outer container, we shrink the arc radius by this padding β€” the whole + // gauge (arc + ticks) then always fits inside whatever box the + // responsive container currently has. + const tickPadding = resolvedTick.show + ? resolvedTick.radiusOffset + + resolvedTick.size + + resolvedTick.labelGap + + resolvedTick.labelSize * 1.5 + : 0; + const maxFitRadius = Math.max( 24, - Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1)) + Math.min( + (availW - tickPadding * 2) / (bounds.w || 1), + (availH - tickPadding * 2) / (bounds.h || 1) + ) ); const outerRadius = resolvedArc.radius @@ -1496,6 +680,58 @@ export function GaugeWidget({ trackSel.attr("opacity", 0); } + // ---- REQUIREMENT 3/4: tick marks + labels ---- + // Ticks don't animate (they're static reference marks), so it's a + // simple remove-and-redraw each time rather than the persistent-node + // + transition pattern used for the bar/needle. + const tickGroup = root.select("g.anedya-gauge-ticks"); + tickGroup.selectAll("*").remove(); + + if (resolvedTick.show) { + const lineStartR = outerRadius + resolvedTick.radiusOffset; + const lineEndR = lineStartR + resolvedTick.size; + const labelR = lineEndR + resolvedTick.labelGap; + + tickValues.forEach((v) => { + const angleDeg = angleScale(v) / DEG2RAD; + + // Tick line: drawn pointing "up" then rotated into place β€” the + // rotate-then-translate idea is the one piece taken from the + // reference D3 gauge's tick-label positioning. + tickGroup + .append("line") + .attr("class", twMerge("anedya-gauge-tick", resolveSlot("tick"))) + .attr("x1", 0) + .attr("y1", -lineStartR) + .attr("x2", 0) + .attr("y2", -lineEndR) + .attr("stroke", resolvedTick.color || "currentColor") + .attr("stroke-width", 1.5) + .attr("transform", `rotate(${angleDeg})`); + + // Tick label: rotate to the tick's angle, translate out to its + // radius, then rotate back β€” keeps every label upright/horizontal + // no matter where it sits around the arc. font-size is set via + // `.style()` (inline style) so `tick.labelSize` always wins over + // any Tailwind class on the `tickLabel` slot. + tickGroup + .append("text") + .attr( + "class", + twMerge("anedya-gauge-tick-label", resolveSlot("tickLabel")) + ) + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .style("font-size", `${resolvedTick.labelSize}px`) + .attr("fill", resolvedTick.labelColor || "currentColor") + .attr( + "transform", + `rotate(${angleDeg}) translate(0, ${-labelR}) rotate(${-angleDeg})` + ) + .text(formatTickLabel(v)); + }); + } + const barGroup = root.select("g.anedya-gauge-bar-group"); const barValue = loading || error ? resolvedProps.min : clampedValue; @@ -1525,23 +761,38 @@ export function GaugeWidget({ ? +path.attr("data-end-angle")! : startA; - path - .datum({ startAngle: startA, endAngle: currentEndAngle, r: outerRadius }) - .transition() - .duration(resolvedAnimation.duration) - .ease(ease) - .attrTween("d", function (d: any) { - const interp = d3.interpolate(d.endAngle, valueAngle); - return (t) => { - d.endAngle = interp(t); - path.attr("data-end-angle", String(d.endAngle)); - return arcGen({ - startAngle: startA, - endAngle: d.endAngle, - r: outerRadius, - })!; - }; - }); + if (resolvedAnimation.show) { + path + .datum({ + startAngle: startA, + endAngle: currentEndAngle, + r: outerRadius, + }) + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("d", function (d: any) { + const interp = d3.interpolate(d.endAngle, valueAngle); + return (t) => { + d.endAngle = interp(t); + path.attr("data-end-angle", String(d.endAngle)); + return arcGen({ + startAngle: startA, + endAngle: d.endAngle, + r: outerRadius, + })!; + }; + }); + } else { + // NEW: animation disabled β€” snap straight to the target angle, no tween + path + .datum({ startAngle: startA, endAngle: valueAngle, r: outerRadius }) + .attr("data-end-angle", String(valueAngle)) + .attr( + "d", + arcGen({ startAngle: startA, endAngle: valueAngle, r: outerRadius })! + ); + } const needleGroup = root.select("g.anedya-gauge-needle"); if (resolvedNeedle.show) { @@ -1554,12 +805,12 @@ export function GaugeWidget({ "circle.anedya-gauge-needle-cap" ); needleEl.attr("class", resolveSlot("needle")); - + needleEl - .attr("class", resolveSlot("needle")) - .attr("fill", resolvedNeedle.needleColor) - .attr("stroke", resolvedNeedle.needleColor) - .attr("opacity", loading ? 0.4 : 1); + .attr("class", resolveSlot("needle")) + .attr("fill", resolvedNeedle.needleColor) + .attr("stroke", resolvedNeedle.needleColor) + .attr("opacity", loading ? 0.4 : 1); Object.entries(shape.attrs).forEach(([k, v]) => needleEl.attr( @@ -1580,12 +831,14 @@ export function GaugeWidget({ ); } cap - .attr("r", resolvedNeedle.capRadius) - .attr("fill", resolvedNeedle.capColor) // ← use capColor - .attr("opacity", loading ? 0.4 : 1); + .attr("r", resolvedNeedle.capRadius) + .attr("fill", resolvedNeedle.capColor) // ← use capColor + .attr("opacity", loading ? 0.4 : 1); const targetDeg = valueAngle / DEG2RAD; - if (resolvedNeedle.animation) { + // NEW: needle now only animates if BOTH the per-needle flag AND the + // global resolvedAnimation.show are true + if (resolvedNeedle.animation && resolvedAnimation.show) { needleGroup .transition() .duration(resolvedAnimation.duration) @@ -1610,8 +863,6 @@ export function GaugeWidget({ } else { needleGroup.attr("opacity", 0); } - - // prevValueRef.current = barValue; }, [ boxWidth, boxHeight, @@ -1637,20 +888,55 @@ export function GaugeWidget({ resolvedNeedle.animation, resolvedAnimation.duration, resolvedAnimation.easing, + resolvedAnimation.show, + resolvedTick.show, + resolvedTick.count, + resolvedTick.size, + resolvedTick.color, + resolvedTick.radiusOffset, + resolvedTick.labelGap, + resolvedTick.labelSize, + resolvedTick.labelColor, + tickValues, + formatTickLabel, resolveSlot, ]); - const handleClick = useCallback( - () => onClick?.(clampedValue), - [onClick, clampedValue] + // const handleClick = useCallback( + // () => onClick?.(clampedValue), + // [onClick, clampedValue] + // ); + + // REQUIREMENT 1: value/unit/label extracted so the exact same markup can + // be placed either below the arc (needle mode) or centered over it + // (no-needle / donut mode) without duplicating JSX. + const valueBlock = ( + <> + {resolvedValueLabel.show && ( + + {displayValue} + {displayUnit && ( + {displayUnit} + )} + + )} + + {displayLabel && ( + {displayLabel} + )} + ); return (
- {resolvedProps.title && ( - {resolvedProps.title} - )} - - + {resolvedProps.title && ( + {resolvedProps.title} + )} */} +
- - - - - - - - - - - {loading ? ( -
-
-
-
- ) : error ? ( - {error} - ) : ( - <> - {resolvedValueLabel.show && ( - {resolvedProps.title} + )} + + {/* REQUIREMENT 1: wrapped in a relative container so the centered + value/label overlay (no-needle mode) can be positioned directly + on top of the arc. min-h-0 keeps this shrinkable inside the + flex-column layout instead of overflowing it. */} +
+ + + + + {/* REQUIREMENT 3/4: tick marks + labels, populated in the D3 draw effect */} + + + + + + + + + {/* REQUIREMENT 1: no needle β†’ treat it like a donut and center the + value/label directly over the arc's visual center (cx, cy). + Position is expressed as a % of the viewBox so it stays correct + at any container size. */} + {!resolvedNeedle.show && !loading && !error && ( +
- {displayValue} - {displayUnit && ( - {displayUnit} - )} - + {valueBlock} +
)} +
- {displayLabel && ( - {displayLabel} - )} - - )} - - {/* {loading ? ( - // Loading skeletons inside SVG - <> - +
- - +
) : error ? ( - - {error} - + {error} ) : ( - <> - {/* Value + Unit */} - {/* - {displayValue} - {displayUnit && ( - - {displayUnit} - - )} - */} - - {/* Label (timestamp) */} - {/* {displayLabel && ( - - {displayLabel} - - )} */} - {/* */} - {/* )} */} - {/*
*/} + // REQUIREMENT 1: needle-mode keeps the original below-the-arc + // layout. No-needle mode already rendered `valueBlock` centered above. + resolvedNeedle.show && valueBlock + )} +
); } diff --git a/src/styles/base.css b/src/styles/base.css index bf42cde9..ea653721 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -27,37 +27,25 @@ } -.anedya-gauge { - container-type: inline-size; +.anedya-gauge-container { + container-type: size; container-name: anedya-gauge; + transition: width 0.25s ease, height 0.25s ease; +} - --anedya-gauge-padding: 0.75rem; - --anedya-gauge-gap: 0.25rem; +.anedya-gauge { + --anedya-gauge-padding: clamp(0.75rem, 0.4rem + 2cqw + 2cqh, 1.5rem); + --anedya-gauge-gap: clamp(0.25rem, 0.1rem + 1cqw + 1cqh, 0.75rem); - --anedya-gauge-title-size: 0.875rem; - --anedya-gauge-value-size: 1.75rem; - --anedya-gauge-unit-size: 0.875rem; - --anedya-gauge-label-size: 0.75rem; - --anedya-gauge-tick-size: 0.625rem; -} + --anedya-gauge-title-size: clamp(0.875rem, 0.6rem + 1.2cqw + 1.2cqh, 1.25rem); + --anedya-gauge-value-size: clamp(1.75rem, 1rem + 4cqw + 4cqh, 3.5rem); + --anedya-gauge-unit-size: clamp(0.875rem, 0.6rem + 1cqw + 1cqh, 1.25rem); + --anedya-gauge-label-size: clamp(0.75rem, 0.5rem + 0.8cqw + 0.8cqh, 1rem); + --anedya-gauge-tick-size: clamp(0.625rem, 0.4rem + 0.6cqw + 0.6cqh, 0.875rem); -@container anedya-gauge (min-width: 260px) { - .anedya-gauge { - --anedya-gauge-padding: 1rem; - --anedya-gauge-value-size: 2.25rem; - --anedya-gauge-unit-size: 1rem; - --anedya-gauge-label-size: 0.875rem; - --anedya-gauge-tick-size: 0.75rem; - } + transition: padding 0.25s ease, gap 0.25s ease; } -@container anedya-gauge (min-width: 380px) { - .anedya-gauge { - --anedya-gauge-padding: 1.25rem; - --anedya-gauge-title-size: 1rem; - --anedya-gauge-value-size: 3rem; - --anedya-gauge-unit-size: 1.125rem; - --anedya-gauge-label-size: 1rem; - --anedya-gauge-tick-size: 0.8125rem; - } +.anedya-gauge > * { + transition: font-size 0.25s ease; } \ No newline at end of file diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index 7f317a1d..8ea9c7ed 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -1,70 +1,4 @@ -// import { GaugeSlot } from "../types/gauge"; -// import { WidgetTheme } from "../types/root"; - -// export const GAUGE_DEFAULT_CLASSES: Record = { -// container: -// "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", -// title: -// "text-[length:var(--anedya-gauge-title-size)] font-medium", -// track: "", -// bar: "", -// segment: "", -// needle: "", -// needleCap: "", -// tick: "", -// tickLabel: -// "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", -// scaleLabel: -// "text-[length:var(--anedya-gauge-tick-size)] font-medium fill-current", -// value: -// "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", -// unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", -// label: "text-[length:var(--anedya-gauge-label-size)]", -// tooltip: -// "pointer-events-none absolute z-10 rounded-md px-2 py-1 text-xs font-medium shadow-md", -// }; - -// export const gaugeLightTheme: WidgetTheme = { -// styles: { -// container: "", -// title: "text-slate-500", -// track: "text-slate-200", // read via `currentColor` on the track path -// bar: "text-indigo-500", -// segment: "", -// needle: "text-slate-700", -// needleCap: "text-slate-700", -// tick: "text-slate-300", -// tickLabel: "text-slate-400", -// scaleLabel: "text-slate-400", -// value: "text-slate-900", -// unit: "text-slate-500", -// label: "text-slate-400", -// tooltip: "bg-slate-900 text-white", -// }, -// }; - -// export const gaugeDarkTheme: WidgetTheme = { -// styles: { -// container: "", -// title: "text-slate-400", -// track: "text-slate-700", -// bar: "text-indigo-400", -// segment: "", -// needle: "text-slate-200", -// needleCap: "text-slate-200", -// tick: "text-slate-600", -// tickLabel: "text-slate-500", -// scaleLabel: "text-slate-500", -// value: "text-white", -// unit: "text-slate-400", -// label: "text-slate-500", -// tooltip: "bg-slate-100 text-slate-900", -// }, -// }; - -// export const gaugeThemes = { light: gaugeLightTheme, dark: gaugeDarkTheme } as const; -// export const DEFAULT_GAUGE_THEME = gaugeLightTheme; - +// themes/gaugeTheme.ts import { GaugeSlot } from "../types/gauge"; import { WidgetTheme } from "../types/root"; @@ -80,19 +14,27 @@ export const GAUGE_DEFAULT_CLASSES: Record = { needleCap: "", value: "text-[length:var(--anedya-gauge-value-size)] font-bold leading-none", label: "text-[length:var(--anedya-gauge-label-size)]", + // NEW β€” tick line has no default utility classes; color comes from theme below. + tick: "", + // NEW β€” font-size is always driven by the `tick.labelSize` prop (set via + // inline style in the widget, which wins over classes), so this only + // needs non-size utilities. + tickLabel: "font-medium select-none", }; export const gaugeLightTheme: WidgetTheme = { styles: { container: "", title: "text-slate-500", - unit: "text-slate-500", + unit: "text-slate-500", track: "text-slate-200", // read via `currentColor` on the track path bar: "text-indigo-500", needle: "text-slate-700", needleCap: "text-slate-700", value: "text-slate-900", label: "text-slate-400", + tick: "text-slate-300", + tickLabel: "text-slate-400", }, }; @@ -100,13 +42,15 @@ export const gaugeDarkTheme: WidgetTheme = { styles: { container: "", title: "text-slate-400", - unit: "text-slate-400", + unit: "text-slate-400", track: "text-slate-700", bar: "text-indigo-400", needle: "text-slate-200", needleCap: "text-slate-200", value: "text-white", label: "text-slate-500", + tick: "text-slate-600", + tickLabel: "text-slate-500", }, }; diff --git a/src/types/gauge.ts b/src/types/gauge.ts index 7768034d..5adbbaf8 100644 --- a/src/types/gauge.ts +++ b/src/types/gauge.ts @@ -1,116 +1,4 @@ -// import { CardSlot } from "./card"; // for BuiltInTheme reuse pattern - -// export type GaugeVariant = "progress" | "needle" | "segmented" | "multiBar"; - -// export type GaugeSlot = -// | "container" -// | "title" -// | "track" -// | "bar" -// | "segment" -// | "needle" -// | "needleCap" -// | "tick" -// | "tickLabel" -// | "scaleLabel" -// | "value" -// | "unit" -// | "label" -// | "tooltip"; - -// export interface GaugeArcConfig { -// /** Degrees, 0 = 12 o'clock, clockwise-positive. */ -// startAngle?: number; -// endAngle?: number; -// radius?: number; -// /** Bar/track thickness in px. Auto-computed from radius if omitted. */ -// thickness?: number; -// cornerRadius?: number; -// /** Gap between concentric bars (multiBar) or track/bar (px). */ -// gap?: number; -// } - -// export interface GaugeTrackConfig { -// show?: boolean; -// color?: string; -// } - -// export type GaugeColor = string | string[]; - -// export interface GaugeBarSpec { -// value: number; -// color?: GaugeColor; -// label?: string; -// } - -// export type NeedleType = "line" | "rounded" | "drop" | "triangle"; - -// export interface GaugeNeedleConfig { -// show?: boolean; -// type?: NeedleType; -// /** Preset or px. Relative to computed radius when a preset is used. */ -// length?: "short" | "medium" | "full" | number; -// width?: number; -// color?: string; -// capRadius?: number; -// animation?: boolean; -// } - -// export interface GaugeLabelsConfig { -// show?: boolean; -// position?: "inside" | "outside"; -// } - -// export interface GaugeValueLabelConfig { -// show?: boolean; -// precision?: number; -// prefix?: string; -// suffix?: string; -// formatter?: (value: number) => string; -// } - -// export interface GaugeNeedleLabelConfig { -// show?: boolean; -// formatter?: (value: number) => string; -// } - -// export interface GaugeScaleConfig { -// minLabel?: string; -// maxLabel?: string; -// } - -// export interface GaugeTicksConfig { -// show?: boolean; -// count?: number; -// position?: "inside" | "outside" | "cross"; -// length?: number; -// labels?: boolean; -// } - -// export interface GaugeSegment { -// from: number; -// to: number; -// color: GaugeColor; -// } - -// export interface GaugeThreshold { -// value: number; -// color: GaugeColor; -// } - -// export interface GaugeGradientConfig { -// colors: string[]; -// } - -// export interface GaugeAnimationConfig { -// duration?: number; -// /* .g. "easeCubicOut", "easeElasticOut". */ -// easing?: string; -// } - -// export interface GaugeTooltipConfig { -// show?: boolean; -// } +// types/gauge.ts export type GaugeSlot = | "container" @@ -121,7 +9,9 @@ export type GaugeSlot = | "needle" | "needleCap" | "value" - | "label"; + | "label" + | "tick" // NEW β€” tick line styling via `styles` prop + | "tickLabel"; // NEW β€” tick number styling via `styles` prop export interface GaugeArcConfig { /** Degrees, 0 = 12 o'clock, clockwise-positive. */ @@ -143,15 +33,42 @@ export type GaugeColor = string | string[]; export type NeedleType = "line" | "rounded" | "drop" | "triangle"; +export type GaugeEasing = + | "linear" + | "quadIn" + | "quadOut" + | "quadInOut" + | "cubicIn" + | "cubicOut" + | "cubicInOut" + | "sinIn" + | "sinOut" + | "sinInOut" + | "expIn" + | "expOut" + | "expInOut" + | "circleIn" + | "circleOut" + | "circleInOut" + | "backIn" + | "backOut" + | "backInOut" + | "elasticIn" + | "elasticOut" + | "elasticInOut" + | "bounceIn" + | "bounceOut" + | "bounceInOut"; + export interface GaugeNeedleConfig { show?: boolean; type?: NeedleType; /** Preset or px. Relative to computed radius when a preset is used. */ length?: "short" | "medium" | "full" | number; width?: number; - color?: string; - needleColor?: string; - capColor?: string; + color?: string; + needleColor?: string; + capColor?: string; capRadius?: number; animation?: boolean; } @@ -164,8 +81,30 @@ export interface GaugeValueLabelConfig { formatter?: (value: number) => string; } +/** REQUIREMENT 3/4: radial min/max tick marks drawn around the arc. */ +export interface GaugeTickConfig { + show?: boolean; + /** Number of INTERVALS between min and max. Default 10 β†’ 11 marks (0,10,20...100 for the 0-100 default). */ + count?: number; + /** Tick line length in px. */ + size?: number; + /** Tick line color (falls back to theme via `currentColor`). */ + color?: string; + /** Gap in px between the arc's outer edge and the start of the tick line. */ + radiusOffset?: number; + /** Gap in px between the end of the tick line and its label. */ + labelGap?: number; + /** Tick label font size in px. */ + labelSize?: number; + /** Tick label color (falls back to theme). */ + labelColor?: string; + /** Custom label formatter β€” receives the raw tick value (e.g. 0, 10, 20...). */ + labelFormat?: (value: number) => string; +} + export interface GaugeAnimationConfig { + show?: boolean; duration?: number; /** Any d3-ease export name, e.g. "easeCubicOut", "easeElasticOut". */ - easing?: string; -} \ No newline at end of file + easing?: GaugeEasing; +} diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index f4b5ff9d..2164dfab 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -95,7 +95,7 @@ export default function App() { className="shadow-lg shadow-amber-400" // <- outer box only, ordinary React convention styles={{ value: "text-red-500 text-5xl", // <- targets the INNER "value" slot specifically - title: "uppercase tracking-wider text-yellow-500", // <- targets the INNER "title" slot specifically + title: "lowercase tracking-wider text-yellow-500", // <- targets the INNER "title" slot specifically }} /> {/* ============================================================ @@ -179,7 +179,7 @@ export default function App() { * ============================================================ */} {/* */} - + + + + + + + + + + +
{ if (!data) return {}; const { value } = data; - if (value > 80) return { title: "πŸ”΄ Critical", color: "#dc2626" }; + if (value > 60) return { title: "πŸ”΄ Critical", color: "#dc2626" }; if (value > 50) return { title: "🟑 Warning", color: "#f59e0b" }; return { title: "🟒 Normal", color: "#10b981" }; }} @@ -366,7 +383,43 @@ export default function App() { {" "} + /> + + {/* val + " km/h", + }} + animation={{ + show: true, + duration: 3000, + easing: "bounceIn", + }} + style={{ backgroundColor: "yellow" }} + /> */} + + {/*

Testing All Gauge Widget Props

+ + + + + */} +
); } diff --git a/test/my-app/src/Test.tsx b/test/my-app/src/Test.tsx index eb4a090b..da9c986f 100644 --- a/test/my-app/src/Test.tsx +++ b/test/my-app/src/Test.tsx @@ -1,398 +1,398 @@ -import React from "react"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "../../../src"; -import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "../../../dist/styles.css"; - -import { relativeTime } from "../../../src/helpers/formatters"; -const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -const token = - "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; -const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; - -const anedya = new Anedya(); -const config = anedya.newConfig(tokenId, token); -const client = anedya.newClient(config); -const node = anedya.newNode(client, nodeId); - -/** - * A reusable theme, shareable across every CardWidget instance in your - * app. Only specify the slots you actually want to change from the - * built-in default β€” anything omitted falls back to lightTheme/darkTheme. - */ -const emeraldTheme = { - classNames: { - container: "bg-emerald-50 border-emerald-200", - title: "text-emerald-700", - value: "text-emerald-900", - label: "text-emerald-500", - }, -}; - - -const commonProps = { node, variable: "humidity" }; - -export default function App() { - return ( +// import React from "react"; +// import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; +// import { CardWidget } from "../../../src"; +// import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; +// import "../../../dist/styles.css"; + +// import { relativeTime } from "../../../src/helpers/formatters"; +// const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; +// const token = +// "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; +// const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; + +// const anedya = new Anedya(); +// const config = anedya.newConfig(tokenId, token); +// const client = anedya.newClient(config); +// const node = anedya.newNode(client, nodeId); + +// /** +// * A reusable theme, shareable across every CardWidget instance in your +// * app. Only specify the slots you actually want to change from the +// * built-in default β€” anything omitted falls back to lightTheme/darkTheme. +// */ +// const emeraldTheme = { +// classNames: { +// container: "bg-emerald-50 border-emerald-200", +// title: "text-emerald-700", +// value: "text-emerald-900", +// label: "text-emerald-500", +// }, +// }; + + +// const commonProps = { node, variable: "humidity" }; + +// export default function App() { +// return ( -
+//
- `Last synced ${relativeTime(ts)}`} +// `Last synced ${relativeTime(ts)}`} - /> - - - {/* ============================================================ - * 2. theme β€” a reusable, shareable WidgetTheme object. Same - * effect across every widget instance that uses it. - * ============================================================ */} - - - {/* Built-in preset names also work directly: */} - - - {/* ============================================================ - * 3. styles vs className β€” THE distinction to understand: - * - * - `styles` (plural, an OBJECT): per-SLOT overrides. - * Keys are "container" | "title" | "value" | "unit" | "label" - * β€” lets you reach INSIDE the widget and style individual - * pieces independently. - * - * - `className` (singular, a STRING): the ordinary React - * convention β€” one class applied ONLY to the widget's - * outermost container element, same as you'd pass to any - * other component. It's merged (via twMerge) with whatever - * styles.container already resolved to, not a - * replacement for it. - * - * This example uses BOTH at once so the difference is visible: - * className adds a shadow to the outer box, styles.value/ - * styles.title style two INNER pieces independently. - * ============================================================ */} - + + +// {/* ============================================================ +// * 2. theme β€” a reusable, shareable WidgetTheme object. Same +// * effect across every widget instance that uses it. +// * ============================================================ */} +// + +// {/* Built-in preset names also work directly: */} +// + +// {/* ============================================================ +// * 3. styles vs className β€” THE distinction to understand: +// * +// * - `styles` (plural, an OBJECT): per-SLOT overrides. +// * Keys are "container" | "title" | "value" | "unit" | "label" +// * β€” lets you reach INSIDE the widget and style individual +// * pieces independently. +// * +// * - `className` (singular, a STRING): the ordinary React +// * convention β€” one class applied ONLY to the widget's +// * outermost container element, same as you'd pass to any +// * other component. It's merged (via twMerge) with whatever +// * styles.container already resolved to, not a +// * replacement for it. +// * +// * This example uses BOTH at once so the difference is visible: +// * className adds a shadow to the outer box, styles.value/ +// * styles.title style two INNER pieces independently. +// * ============================================================ */} +// - - {/* ============================================================ - * 4. Plain CSS classes β€” styles works with ANY class source, - * not just Tailwind. These reference plain hand-written CSS - * classes (e.g. defined in a .css file this app already imports). - * ============================================================ */} - {/* */} - - {/* ============================================================ - * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` - * work exactly as they do anywhere else in your app, because - * styles just forwards whatever string you write straight - * to `className`. This widget does NOT have its own custom - * breakpoint system β€” these prefixes are compiled by YOUR - * project's Tailwind config and respond to the BROWSER VIEWPORT, - * same as native Tailwind everywhere else. If your own - * tailwind.config.js customizes `theme.screens`, these prefixes - * automatically follow that customization too β€” nothing to - * configure on the widget's side. - * ============================================================ */} - {/* */} - - {/* ============================================================ - * 6. formatValue / labelText β€” simple formatting hooks, distinct - * from styling. formatValue controls the displayed number's - * text; labelText controls the caption under it. - * ============================================================ */} - {/* `${v.toFixed(2)} % RH`} - labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} +// /> + +// {/* ============================================================ +// * 4. Plain CSS classes β€” styles works with ANY class source, +// * not just Tailwind. These reference plain hand-written CSS +// * classes (e.g. defined in a .css file this app already imports). +// * ============================================================ */} +// {/* */} + +// {/* ============================================================ +// * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` +// * work exactly as they do anywhere else in your app, because +// * styles just forwards whatever string you write straight +// * to `className`. This widget does NOT have its own custom +// * breakpoint system β€” these prefixes are compiled by YOUR +// * project's Tailwind config and respond to the BROWSER VIEWPORT, +// * same as native Tailwind everywhere else. If your own +// * tailwind.config.js customizes `theme.screens`, these prefixes +// * automatically follow that customization too β€” nothing to +// * configure on the widget's side. +// * ============================================================ */} +// {/* */} + +// {/* ============================================================ +// * 6. formatValue / labelText β€” simple formatting hooks, distinct +// * from styling. formatValue controls the displayed number's +// * text; labelText controls the caption under it. +// * ============================================================ */} +// {/* `${v.toFixed(2)} % RH`} +// labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - /> */} - - {/* ============================================================ - * 7. onStyleChange β€” conditional class overrides driven by the - * RAW fetched data ({ value, timestamp }), always applied on top - * of everything else (theme, styles, className). - * ============================================================ */} - {/* { - if (!data) return; - - if (data.value > 80) { - return { - title: "High Humidity", - theme: "dark", - styles: { - value: "text-red-500" - } - }; - } - - return { - title: "Humidity", - theme: "light" - }; - }} +// /> */} + +// {/* ============================================================ +// * 7. onStyleChange β€” conditional class overrides driven by the +// * RAW fetched data ({ value, timestamp }), always applied on top +// * of everything else (theme, styles, className). +// * ============================================================ */} +// {/* { +// if (!data) return; + +// if (data.value > 80) { +// return { +// title: "High Humidity", +// theme: "dark", +// styles: { +// value: "text-red-500" +// } +// }; +// } + +// return { +// title: "Humidity", +// theme: "light" +// }; +// }} - /> */} - - {/* ============================================================ - * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, - * applied as inline styles on the container, independent of the - * whole styles/theme system. - * ============================================================ */} - {/* */} +// /> */} + +// {/* ============================================================ +// * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, +// * applied as inline styles on the container, independent of the +// * whole styles/theme system. +// * ============================================================ */} +// {/* */} - {/* { - // "Hello"; - // }, - // }} - // labels={{ - // show: true, - // position: "outside", - // }} - // scale={{ - // minLabel: "Hello", - // maxLabel: "World", - // }} - // ticks={{ - // show: true, - // count: 10, - // position: "outside", - // length: 10, - // labels: true, - // }} - animation={{ - duration: 4000, - easing: "easeElasticOut", // easeCubicOut, easeElasticOut - }} - // tooltip={{ - // show:false, - // }} - // classNames={{ - // title: "text-white", - // tickLabel: "text-white text-lg", - // label: "text-red", - // value: "text-white", - // }} - theme="dark" - /> */} - - - - - - - style={{ - backgroundColor: "#1e1e2f", - borderRadius: "16px", - padding: "10px", - }} - // 'styles' affects specific internal SVG/HTML slots via Tailwind classes - styles={{ - container: "border border-gray-700", // merges with outer wrapper - title: "text-purple-400 text-xs uppercase tracking-wider", - value: "text-white text-2xl font-mono", - unit: "text-gray-400 text-sm", - label: "text-gray-500 text-[10px]", - bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients - needle: "stroke-pink-400 stroke-2", - needleCap: "fill-pink-400", - }} - /> - - - - - - - - {/* // 1. Show a custom static text */} - "Last reading"} // Always shows "Last reading" - /> - - {/* // 2. Format the timestamp exactly how you want */} - - `Updated at ${new Date(timestamp).toLocaleString("en-US", { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - })}` - } - // Output: "Updated at 02:30:45 PM" - /> - - {/* // 3. Show relative time with custom wording */} - { - const diff = Math.floor((Date.now() - timestamp) / 60000); - if (diff < 1) return "Just now"; - if (diff < 60) return `${diff} min ago`; - return `${Math.floor(diff / 60)} hours ago`; - }} - /> - - {/* // 4. Hide the label entirely (return null or empty string) */} - null} // No label shown - /> -
- ); -} +// {/* { +// // "Hello"; +// // }, +// // }} +// // labels={{ +// // show: true, +// // position: "outside", +// // }} +// // scale={{ +// // minLabel: "Hello", +// // maxLabel: "World", +// // }} +// // ticks={{ +// // show: true, +// // count: 10, +// // position: "outside", +// // length: 10, +// // labels: true, +// // }} +// animation={{ +// duration: 4000, +// easing: "easeElasticOut", // easeCubicOut, easeElasticOut +// }} +// // tooltip={{ +// // show:false, +// // }} +// // classNames={{ +// // title: "text-white", +// // tickLabel: "text-white text-lg", +// // label: "text-red", +// // value: "text-white", +// // }} +// theme="dark" +// /> */} + +// + +// + +// +// style={{ +// backgroundColor: "#1e1e2f", +// borderRadius: "16px", +// padding: "10px", +// }} +// // 'styles' affects specific internal SVG/HTML slots via Tailwind classes +// styles={{ +// container: "border border-gray-700", // merges with outer wrapper +// title: "text-purple-400 text-xs uppercase tracking-wider", +// value: "text-white text-2xl font-mono", +// unit: "text-gray-400 text-sm", +// label: "text-gray-500 text-[10px]", +// bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients +// needle: "stroke-pink-400 stroke-2", +// needleCap: "fill-pink-400", +// }} +// /> + +// + +// + +// + +// {/* // 1. Show a custom static text */} +// "Last reading"} // Always shows "Last reading" +// /> + +// {/* // 2. Format the timestamp exactly how you want */} +// +// `Updated at ${new Date(timestamp).toLocaleString("en-US", { +// hour: "2-digit", +// minute: "2-digit", +// second: "2-digit", +// })}` +// } +// // Output: "Updated at 02:30:45 PM" +// /> + +// {/* // 3. Show relative time with custom wording */} +// { +// const diff = Math.floor((Date.now() - timestamp) / 60000); +// if (diff < 1) return "Just now"; +// if (diff < 60) return `${diff} min ago`; +// return `${Math.floor(diff / 60)} hours ago`; +// }} +// /> + +// {/* // 4. Hide the label entirely (return null or empty string) */} +// null} // No label shown +// /> +//
+// ); +// } { /* @@ -401,3 +401,935 @@ export default function App() { //npm run dev //send this file tp yash to copy paste */ } + + + +// import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +// import * as d3 from "d3"; +// import { twMerge } from "tailwind-merge"; +// import { AnedyaWidgetBaseProps } from "../../common"; +// import { SlotClassNames, WidgetTheme } from "../../types/root"; +// import { +// GaugeAnimationConfig, +// GaugeArcConfig, +// GaugeBarSpec, +// GaugeColor, +// GaugeLabelsConfig, +// GaugeNeedleConfig, +// GaugeNeedleLabelConfig, +// GaugeScaleConfig, +// GaugeSegment, +// GaugeSlot, +// GaugeThreshold, +// GaugeTicksConfig, +// GaugeTooltipConfig, +// GaugeTrackConfig, +// GaugeValueLabelConfig, +// GaugeVariant, +// } from "../../types/gauge"; +// import { +// DEFAULT_GAUGE_THEME, +// GAUGE_DEFAULT_CLASSES, +// gaugeDarkTheme, +// gaugeLightTheme, +// } from "../../themes/gaugeTheme"; +// import { useResizeObserver } from "../../hooks/useResizeObserver"; + +// export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { +// variant?: GaugeVariant; +// /** Used before live data arrives, or standalone in dummy-data mode. */ +// value?: number; +// min?: number; +// max?: number; +// size?: number; +// responsive?: boolean; + +// arc?: GaugeArcConfig; +// track?: GaugeTrackConfig; +// fillMode?: "progress" | "solid"; +// /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ +// color?: GaugeColor; +// bars?: GaugeBarSpec[]; + +// needle?: GaugeNeedleConfig; +// labels?: GaugeLabelsConfig; +// valueLabel?: GaugeValueLabelConfig; +// needleLabel?: GaugeNeedleLabelConfig; +// scale?: GaugeScaleConfig; +// ticks?: GaugeTicksConfig; +// segments?: GaugeSegment[]; +// thresholds?: GaugeThreshold[]; +// animation?: GaugeAnimationConfig; +// tooltip?: GaugeTooltipConfig; + +// classNames?: SlotClassNames; +// style?: React.CSSProperties; + +// onClick?: (value: number) => void; +// onHover?: (value: number | null) => void; +// onValueChange?: (value: number) => void; +// } + +// const DEG2RAD = Math.PI / 180; + +// const DEFAULT_ARC: Required> = { +// startAngle: -90, +// endAngle: 90, +// cornerRadius: 0, +// gap: 6, +// }; + +// const DEFAULT_ANIMATION: Required = { +// duration: 750, +// easing: "easeCubicOut", +// }; + +// function resolveEase(name: string) { +// return (d3 as any)[name] ?? d3.easeCubicOut; +// } + +// function needlePixelLength( +// length: GaugeNeedleConfig["length"], +// radius: number +// ) { +// if (typeof length === "number") return length; +// switch (length) { +// case "short": +// return radius * 0.55; +// case "full": +// return radius * 0.95; +// case "medium": +// default: +// return radius * 0.75; +// } +// } + +// /** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ +// function needleShape( +// type: NonNullable, +// length: number, +// width: number +// ) { +// const w = width; +// switch (type) { +// case "line": +// return { +// tag: "line", +// attrs: { +// x1: 0, +// y1: 0, +// x2: 0, +// y2: -length, +// strokeWidth: w, +// strokeLinecap: "butt", +// }, +// }; +// case "rounded": +// return { +// tag: "line", +// attrs: { +// x1: 0, +// y1: 0, +// x2: 0, +// y2: -length, +// strokeWidth: w, +// strokeLinecap: "round", +// }, +// }; +// case "triangle": { +// const half = w / 2; +// return { +// tag: "polygon", +// attrs: { +// points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ +// -length * 0.15 +// }`, +// }, +// }; +// } +// case "drop": +// default: { +// const half = w / 2; +// // Teardrop: rounded base, sharp tip. +// const d = `M ${-half} 0 +// C ${-half} ${-length * 0.35}, ${-w} ${ +// -length * 0.7 +// }, 0 ${-length} +// C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 +// A ${half} ${half} 0 1 1 ${-half} 0 Z`; +// return { tag: "path", attrs: { d } }; +// } +// } +// } + +// function isGradientColor(c?: GaugeColor): c is string[] { +// return Array.isArray(c) && c.length >= 2; +// } + +// /** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ +// function resolveFill( +// defs: d3.Selection, +// id: string, +// color: GaugeColor | undefined, +// fallback: string +// ): string { +// if (!color) return fallback; +// if (!isGradientColor(color)) return color; + +// let grad = defs.select(`#${id}`); +// if (grad.empty()) { +// grad = defs.append("linearGradient").attr("id", id); +// } +// grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); +// grad.selectAll("stop").remove(); +// color.forEach((c, i) => +// grad +// .append("stop") +// .attr("offset", `${(i / (color.length - 1)) * 100}%`) +// .attr("stop-color", c) +// ); +// return `url(#${id})`; +// } + +// /** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ +// function getArcBounds(startDeg: number, endDeg: number) { +// const lo = Math.min(startDeg, endDeg); +// const hi = Math.max(startDeg, endDeg); +// const angles = [startDeg, endDeg]; +// for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); + +// let minX = Infinity, +// maxX = -Infinity, +// minY = Infinity, +// maxY = -Infinity; +// angles.forEach((deg) => { +// const a = deg * DEG2RAD; +// const x = Math.sin(a); +// const y = -Math.cos(a); +// minX = Math.min(minX, x); +// maxX = Math.max(maxX, x); +// minY = Math.min(minY, y); +// maxY = Math.max(maxY, y); +// }); +// return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; +// } + +// export function GaugeWidget({ +// node, +// variable, +// title, +// theme, +// className, +// style, +// width, +// height, +// minWidth = 160, +// maxWidth = 480, +// minHeight = 160, +// maxHeight = 480, +// aspectRatio, + +// variant = "progress", +// value: valueProp, +// min = 0, +// max = 100, +// size, +// responsive = true, + +// arc, +// track, +// fillMode = "progress", +// color, +// bars, + +// needle, +// labels, +// valueLabel, +// needleLabel, +// scale, +// ticks, +// segments, +// thresholds, +// animation, +// tooltip, + +// classNames = {}, +// onClick, +// onHover, +// onValueChange, +// }: GaugeWidgetProps) { +// const svgRef = useRef(null); +// const tooltipRef = useRef(null); +// const prevValueRef = useRef(min); + +// const [fetchedValue, setFetchedValue] = useState(null); +// const [hoverValue, setHoverValue] = useState(null); + +// // ---- Live data fetch (mirrors CardWidget) ---- +// useEffect(() => { +// if (!node) return; +// let mounted = true; + +// node +// .getLatestData(variable) +// .then((res: any) => { +// if (!mounted) return; +// if (res?.isSuccess && res?.isDataAvailable) { +// setFetchedValue(res.data.value); +// } +// }) +// .catch(() => { +// /* fall back to `value` prop / dummy data silently */ +// }); + +// return () => { +// mounted = false; +// }; +// }, [node, variable]); + +// const rawValue = fetchedValue ?? valueProp ?? min; +// const clampedValue = Math.min(max, Math.max(min, rawValue)); + +// useEffect(() => { +// onValueChange?.(clampedValue); +// }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps + +// // ---- Responsive sizing ---- +// const { ref: wrapperRef, size: dims } = useResizeObserver( +// responsive && size == null +// ); + +// // ---- Resolved config (defaults per variant) ---- +// const resolvedArc = { ...DEFAULT_ARC, ...arc }; + +// const resolvedTrack: Required = { +// show: track?.show ?? true, +// color: track?.color ?? "", +// }; + +// const needleShownByDefault = variant === "progress" || variant === "needle"; + +// const resolvedNeedle: Required> & { +// length: NonNullable; +// } = { +// show: needle?.show ?? needleShownByDefault, +// type: needle?.type ?? "rounded", +// length: needle?.length ?? "medium", +// width: needle?.width ?? 4, +// color: needle?.color ?? "", +// capRadius: needle?.capRadius ?? 6, +// animation: needle?.animation ?? true, +// }; + +// const resolvedLabels: Required = { +// show: labels?.show ?? true, +// position: labels?.position ?? "outside", +// }; + +// const resolvedValueLabel: Required< +// Omit +// > & { formatter?: (v: number) => string } = { +// show: valueLabel?.show ?? true, +// precision: valueLabel?.precision ?? 0, +// prefix: valueLabel?.prefix ?? "", +// suffix: valueLabel?.suffix ?? "", +// formatter: valueLabel?.formatter, +// }; + +// const resolvedNeedleLabel: Required< +// Omit +// > & { formatter?: (v: number) => string } = { +// show: needleLabel?.show ?? false, +// formatter: needleLabel?.formatter, +// }; + +// const resolvedTicks: Required = { +// show: ticks?.show ?? (variant === "needle" || variant === "segmented"), +// count: ticks?.count ?? 5, +// position: ticks?.position ?? "outside", +// length: ticks?.length ?? 6, +// labels: ticks?.labels ?? true, +// }; + +// const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; + +// const resolvedTooltip: Required = { +// show: tooltip?.show ?? true, +// }; + +// // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- +// const resolvedTheme: WidgetTheme = +// theme === "dark" +// ? gaugeDarkTheme +// : theme === "light" +// ? gaugeLightTheme +// : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; + +// const resolveSlot = useCallback( +// (slot: GaugeSlot) => +// twMerge( +// GAUGE_DEFAULT_CLASSES[slot], +// resolvedTheme.styles[slot], +// classNames[slot] +// ), +// [resolvedTheme, classNames] +// ); + +// const boxWidth = size ?? width ?? (dims.width || 240); + +// const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); + +// const bounds = useMemo( +// () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), +// [resolvedArc.startAngle, resolvedArc.endAngle] +// ); + +// const pad = 8; +// // Reserve room below the arc for value/needle-label/variable text so +// // the dome never gets crowded β€” bigger reserve when the value label is on. +// const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + +// // Ticks (and their number labels) draw *outside* the arc's own radius, +// // so the radius-fit math below must shrink the arc enough to leave +// // room for them β€” otherwise tick labels get clipped by the SVG +// // viewBox, which looked like "some ticks are hidden". +// const tickOverflow = +// resolvedTicks.show && resolvedTicks.position !== "inside" +// ? resolvedTicks.length + (resolvedTicks.labels ? 26 : 8) +// : 0; +// // Scale min/max labels also draw past the arc's radius at the two ends. +// const scaleLabelOverflow = +// resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) ? 24 : 0; +// const edgeOverflow = Math.max(tickOverflow, scaleLabelOverflow); + +// const availW = boxWidth - pad * 2 - edgeOverflow * 2; +// const availH = boxHeight * (1 - textReserve) - pad * 2 - edgeOverflow; + +// const outerRadius = +// resolvedArc.radius ?? +// Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); + +// const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); + +// // Center the arc's bounding box within the available width, anchor its top at `pad`. +// const cx = +// pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; +// const cy = pad - bounds.minY * outerRadius; + +// const angleScale = useMemo( +// () => +// d3 +// .scaleLinear() +// .domain([min, max]) +// .range([ +// resolvedArc.startAngle * DEG2RAD, +// resolvedArc.endAngle * DEG2RAD, +// ]) +// .clamp(true), +// [min, max, resolvedArc.startAngle, resolvedArc.endAngle] +// ); + +// // ---- D3 draw ---- +// useEffect(() => { +// if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; + +// const svg = d3.select(svgRef.current); +// const defs = svg.select("defs"); +// const root = svg.select("g.anedya-gauge-root"); +// root.attr("transform", `translate(${cx},${cy})`); + +// const ease = resolveEase(resolvedAnimation.easing); +// const arcGen = d3 +// .arc<{ startAngle: number; endAngle: number; r: number }>() +// .innerRadius((d) => d.r - thickness) +// .outerRadius((d) => d.r) +// .cornerRadius(resolvedArc.cornerRadius) +// .startAngle((d) => d.startAngle) +// .endAngle((d) => d.endAngle); + +// const startA = resolvedArc.startAngle * DEG2RAD; +// const endA = resolvedArc.endAngle * DEG2RAD; + +// // --- Track --- +// const trackSel = root.select( +// "path.anedya-gauge-track-path" +// ); +// if (resolvedTrack.show && variant !== "multiBar") { +// trackSel +// .attr( +// "d", +// arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! +// ) +// .attr("fill", resolvedTrack.color || "currentColor") +// .attr("opacity", 1); +// } else { +// trackSel.attr("opacity", 0); +// } + +// // --- Bar (progress / solid / segmented base) --- +// const barGroup = root.select("g.anedya-gauge-bar-group"); +// barGroup.selectAll("*").remove(); + +// if (variant === "multiBar" && bars?.length) { +// const maxBars = bars.slice(0, 10); +// maxBars.forEach((bar, i) => { +// const r = outerRadius - i * (thickness + resolvedArc.gap); +// if (resolvedTrack.show) { +// barGroup +// .append("path") +// .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) +// .attr( +// "class", +// twMerge("anedya-gauge-multibar-track", resolveSlot("track")) +// ) +// .attr("fill", resolvedTrack.color || "currentColor") +// .attr("stroke", "none"); +// } +// const valAngle = d3 +// .scaleLinear() +// .domain([min, max]) +// .range([startA, endA]) +// .clamp(true)(bar.value); + +// const barFill = resolveFill( +// defs, +// `anedya-gauge-bar-fill-${i}`, +// bar.color, +// "currentColor" +// ); + +// const path = barGroup +// .append("path") +// .attr("class", resolveSlot("bar")) +// .attr("fill", barFill) +// .attr("stroke", "none"); +// path +// .datum({ startAngle: startA, endAngle: startA, r }) +// .attr("d", arcGen as any) +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("d", function (d: any) { +// const i2 = d3.interpolate(d.endAngle, valAngle); +// return (t) => { +// d.endAngle = i2(t); +// return arcGen(d)!; +// }; +// }); +// }); +// } else if (segments?.length) { +// const scaleAngle = d3 +// .scaleLinear() +// .domain([min, max]) +// .range([startA, endA]) +// .clamp(true); +// // Half the configured gap, converted from px to radians at this radius, +// // so adjoining segments get visible separation like distinct blocks. +// const gapRad = resolvedArc.gap / 2 / outerRadius || 0; + +// const segArcGen = d3 +// .arc<{ startAngle: number; endAngle: number; r: number }>() +// .innerRadius((d) => d.r - thickness) +// .outerRadius((d) => d.r) +// .cornerRadius(resolvedArc.cornerRadius || thickness / 4) +// .startAngle((d) => d.startAngle) +// .endAngle((d) => d.endAngle); + +// segments.forEach((seg, idx) => { +// const segStart = scaleAngle(seg.from) + gapRad; +// const segEnd = scaleAngle(seg.to) - gapRad; +// if (segEnd <= segStart) return; + +// const fill = resolveFill( +// defs, +// `anedya-gauge-segment-fill-${idx}`, +// seg.color, +// "currentColor" +// ); +// barGroup +// .append("path") +// .attr("class", resolveSlot("segment")) +// .attr("fill", fill) +// .attr("stroke", "none") +// .attr( +// "d", +// segArcGen({ +// startAngle: segStart, +// endAngle: segEnd, +// r: outerRadius, +// })! +// ); +// }); +// } else { +// const valueAngle = angleScale(clampedValue); +// const barColorRaw: GaugeColor | undefined = +// color ?? +// (thresholds?.length +// ? [...thresholds] +// .sort((a, b) => a.value - b.value) +// .reduce( +// (acc, th) => (clampedValue >= th.value ? th.color : acc), +// thresholds[0].color +// ) +// : undefined); + +// const barFill = resolveFill( +// defs, +// "anedya-gauge-bar-fill", +// barColorRaw, +// "currentColor" +// ); + +// const path = barGroup +// .append("path") +// .attr("class", resolveSlot("bar")) +// .attr("fill", barFill) +// .attr("stroke", "none"); + +// const from = fillMode === "solid" ? startA : startA; +// const to = fillMode === "solid" ? endA : valueAngle; + +// path +// .datum({ +// startAngle: startA, +// endAngle: +// prevValueRef.current != null +// ? angleScale(prevValueRef.current) +// : startA, +// r: outerRadius, +// }) +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("d", function (d: any) { +// const i2 = d3.interpolate(d.endAngle, to); +// return (t) => { +// d.endAngle = i2(t); +// return arcGen({ +// startAngle: from, +// endAngle: d.endAngle, +// r: outerRadius, +// })!; +// }; +// }); +// } + +// // --- Ticks --- +// const tickGroup = root.select("g.anedya-gauge-ticks"); +// tickGroup.selectAll("*").remove(); +// if (resolvedTicks.show) { +// const count = Math.max(2, resolvedTicks.count); +// const tickR = +// resolvedTicks.position === "inside" +// ? outerRadius - thickness +// : resolvedTicks.position === "cross" +// ? outerRadius - thickness / 2 +// : outerRadius + 4; +// d3.range(count).forEach((i) => { +// const t = i / (count - 1); +// const tv = min + t * (max - min); +// const a = angleScale(tv); +// const x1 = Math.sin(a) * tickR; +// const y1 = -Math.cos(a) * tickR; +// const x2 = +// Math.sin(a) * +// (tickR + +// (resolvedTicks.position === "inside" +// ? -resolvedTicks.length +// : resolvedTicks.length)); +// const y2 = +// -Math.cos(a) * +// (tickR + +// (resolvedTicks.position === "inside" +// ? -resolvedTicks.length +// : resolvedTicks.length)); +// tickGroup +// .append("line") +// .attr("class", resolveSlot("tick")) +// .attr("stroke", "currentColor") +// .attr("x1", x1) +// .attr("y1", y1) +// .attr("x2", x2) +// .attr("y2", y2); + +// if (resolvedTicks.labels) { +// const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); +// const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); +// tickGroup +// .append("text") +// .attr("class", resolveSlot("tickLabel")) +// .attr("x", lx) +// .attr("y", ly) +// .attr("text-anchor", "middle") +// .attr("dominant-baseline", "middle") +// .text(String(Math.round(tv))); +// } +// }); +// } +// // --- Scale min/max labels (drawn at the arc's real start/end points, +// // not floated at the container's edges) --- +// const scaleLabelGroup = root.select( +// "g.anedya-gauge-scale-labels" +// ); +// scaleLabelGroup.selectAll("*").remove(); +// if (resolvedLabels.show && (scale?.minLabel || scale?.maxLabel)) { +// const labelR = +// outerRadius + +// (resolvedTicks.show ? resolvedTicks.length + 16 : 12); + +// const drawScaleLabel = (angle: number, text: string) => { +// const x = Math.sin(angle) * labelR; +// const y = -Math.cos(angle) * labelR; +// // Anchor away from the point so the label doesn't overlap the arc: +// // labels on the left side end at x, labels on the right start at x. +// const anchor = x < -2 ? "end" : x > 2 ? "start" : "middle"; +// scaleLabelGroup +// .append("text") +// .attr("class", resolveSlot("scaleLabel")) +// .attr("x", x) +// .attr("y", y) +// .attr("text-anchor", anchor) +// .attr("dominant-baseline", "middle") +// .text(text); +// }; + +// if (scale?.minLabel) drawScaleLabel(startA, scale.minLabel); +// if (scale?.maxLabel) drawScaleLabel(endA, scale.maxLabel); +// } + +// // --- Needle --- +// const needleGroup = root.select("g.anedya-gauge-needle"); +// if (resolvedNeedle.show && variant !== "multiBar") { +// const len = needlePixelLength(resolvedNeedle.length, outerRadius); +// const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); + +// needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); +// const needleEl = needleGroup.insert( +// shape.tag as any, +// "circle.anedya-gauge-needle-cap" +// ); +// needleEl +// .attr("class", resolveSlot("needle")) +// .attr("fill", resolvedNeedle.color || "currentColor") +// .attr("stroke", resolvedNeedle.color || "currentColor"); +// Object.entries(shape.attrs).forEach(([k, v]) => +// needleEl.attr( +// k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), +// v as any +// ) +// ); + +// let cap = needleGroup.select( +// "circle.anedya-gauge-needle-cap" +// ); +// if (cap.empty()) { +// cap = needleGroup +// .append("circle") +// .attr( +// "class", +// twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) +// ); +// } +// cap +// .attr("r", resolvedNeedle.capRadius) +// .attr("fill", resolvedNeedle.color || "currentColor"); + +// const targetDeg = angleScale(clampedValue) / DEG2RAD; +// if (resolvedNeedle.animation) { +// needleGroup +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("transform", function () { +// const current = needleGroup.attr("data-angle") +// ? +needleGroup.attr("data-angle")! +// : startA / DEG2RAD; +// const interp = d3.interpolate(current, targetDeg); +// return (t) => { +// const a = interp(t); +// needleGroup.attr("data-angle", String(a)); +// return `rotate(${a})`; +// }; +// }); +// } else { +// needleGroup +// .attr("transform", `rotate(${targetDeg})`) +// .attr("data-angle", String(targetDeg)); +// } +// needleGroup.attr("opacity", 1); +// } else { +// needleGroup.attr("opacity", 0); +// } + +// prevValueRef.current = clampedValue; +// }, [ +// boxWidth, +// boxHeight, +// cx, +// cy, +// outerRadius, +// thickness, +// variant, +// clampedValue, +// min, +// max, +// fillMode, +// color, +// JSON.stringify(bars), +// JSON.stringify(segments), +// JSON.stringify(thresholds), +// resolvedTrack.show, +// resolvedTrack.color, +// resolvedNeedle.show, +// resolvedNeedle.type, +// resolvedNeedle.length, +// resolvedNeedle.width, +// resolvedNeedle.color, +// resolvedNeedle.capRadius, +// resolvedNeedle.animation, +// resolvedTicks.show, +// resolvedTicks.count, +// resolvedTicks.position, +// resolvedTicks.length, +// resolvedTicks.labels, +// resolvedAnimation.duration, +// resolvedAnimation.easing, +// resolveSlot, +// resolvedLabels.show, +// scale?.minLabel, +// scale?.maxLabel, +// ]); + +// // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- +// const handlePointerMove = useCallback( +// (e: React.PointerEvent) => { +// if (!resolvedTooltip.show && !onHover) return; +// const rect = svgRef.current!.getBoundingClientRect(); +// const x = e.clientX - rect.left - cx; +// const y = e.clientY - rect.top - cy; +// const dist = Math.hypot(x, y); +// if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { +// setHoverValue(null); +// onHover?.(null); +// return; +// } +// let a = Math.atan2(x, -y); +// const hv = angleScale.invert(a); +// const clamped = Math.min(max, Math.max(min, hv)); +// setHoverValue(clamped); +// onHover?.(clamped); +// if (tooltipRef.current) { +// tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; +// tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; +// } +// }, +// [ +// cx, +// cy, +// outerRadius, +// thickness, +// angleScale, +// min, +// max, +// onHover, +// resolvedTooltip.show, +// ] +// ); + +// const handlePointerLeave = useCallback(() => { +// setHoverValue(null); +// onHover?.(null); +// }, [onHover]); + +// const handleClick = useCallback( +// () => onClick?.(clampedValue), +// [onClick, clampedValue] +// ); + +// const formattedValue = resolvedValueLabel.formatter +// ? resolvedValueLabel.formatter(clampedValue) +// : `${resolvedValueLabel.prefix}${clampedValue.toFixed( +// resolvedValueLabel.precision +// )}${resolvedValueLabel.suffix}`; + +// const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); + +// return ( +//
+// {title && {title}} + +// +// +// +// +// +// +// +// +// +// +// +// + +// {/* {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( +//
+// {scale?.minLabel} +// {scale?.maxLabel} +//
+// )} */} + +// {resolvedValueLabel.show && ( +// {formattedValue} +// )} + +// {resolvedNeedleLabel.show && needleLabelText && ( +// {needleLabelText} +// )} + +// {variable && {variable}} + +// {resolvedTooltip.show && hoverValue != null && ( +//
+// {hoverValue.toFixed(resolvedValueLabel.precision)} +//
+// )} +//
+// ); +// } From e5bec15eaa6536e9c62374165250134bbb51ff8c Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Sat, 25 Jul 2026 23:13:55 +0530 Subject: [PATCH 42/66] added updates --- LICENSE | 222 +++++++++++-- README.md | 92 +++++- src/common.ts | 4 +- src/components/CardWidget.tsx | 129 +++++--- src/helpers/formatters.ts | 45 +-- src/themes/defaultTheme.ts | 8 +- test/my-app/package-lock.json | 599 +++++++++++++++++++++++++++++++++- test/my-app/package.json | 6 +- test/my-app/src/App.jsx | 32 +- test/my-app/src/index.css | 2 + test/my-app/vite.config.js | 4 +- 11 files changed, 1036 insertions(+), 107 deletions(-) diff --git a/LICENSE b/LICENSE index 7bce2a58..f49a4e16 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -MIT License - -Copyright (c) 2026 Anedya Systems - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md index 41b133eb..677c51ad 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [How props are resolved](#how-props-are-resolved) - [Formatting vs rendering](#formatting-vs-rendering) - [The last-updated label](#the-last-updated-label) +- [Error & empty states](#error--empty-states) - [Formatters export](#formatters-export) - [Sizing](#sizing) - [Responsive sizing](#responsive-sizing) @@ -250,7 +251,7 @@ For values that need unit-aware scaling (bytes, durations, lengths, etc.), pass // renders "2d 4h 12m" - + // renders "1.25" + "km" ``` @@ -272,7 +273,7 @@ Available presets: { locale?: string; // BCP 47 tag, e.g. "en-IN" β€” defaults to browser locale binary?: boolean; // bytes only: 1024-based (KiB/MiB) vs 1000-based (KB/MB) - precision?: number; // decimal places for the scaled number + formatOptions?: number; // decimal places for the scaled number } ``` @@ -287,12 +288,12 @@ Available presets: // "123.456" (German uses "." as the thousands separator, "," as the decimal point) ``` -- **`precision`** β€” control decimal places in the *scaled* output (not the raw value). Useful when the default rounding is too coarse for scientific/financial data, or you want whole numbers for a cleaner dashboard look: +- **`formatOptions`** β€” control decimal places in the *scaled* output (not the raw value). Useful when the default rounding is too coarse for scientific/financial data, or you want whole numbers for a cleaner dashboard look: ```tsx - + // "512.34" + "MB" β€” more decimal places than the default - + // "512" + "MB" β€” whole number, no decimals ``` @@ -329,6 +330,17 @@ Available presets: By default, the label under the value shows a fixed clock time (`"Updated 14:32:10"`). This can be changed with `labelFormat`, or fully replaced with `labelText`. +##### `timezone` β€” override auto-detection + +```tsx + +// shows the timestamp converted to Eastern time, regardless of the visitor's own browser timezone +``` + +If omitted, the widget uses `Intl.DateTimeFormat().resolvedOptions().timeZone` β€” the browser's own detected timezone. Pass any IANA timezone name (e.g. `"Asia/Kolkata"`, `"Europe/London"`) to force a specific one instead β€” useful for dashboards where all viewers should see times in the device's local timezone rather than their own. + +`timezone` affects the `time`, `date`, and `datetime` label presets. It has no effect on `relative` (a time difference is timezone-independent) or `iso` (ISO 8601 output is always UTC by definition). + ##### `labelFormat` β€” named presets ```tsx @@ -374,6 +386,76 @@ import { relativeTime } from "public-widget-sdk/formatters"; --- + +#### Error & empty states + +The card distinguishes between three outcomes of a fetch, each rendered differently: + +| State | When it happens | Default appearance | +|---|---|---| +| Success | Data was fetched normally | The formatted value, unit, and label | +| Error | The fetch failed (network error, bad request, etc.) | The error message, styled via the `error` slot | +| Empty | The fetch succeeded, but no data exists yet for this variable | `"N/A"`, styled via the `empty` slot | + +Both `error` and `empty` are real slots, so they pick up theme colors automatically and can be restyled the same way as any other slot: + +```tsx + +``` + +##### `renderError` / `renderEmpty` β€” full custom rendering + +For full control beyond just restyling text, `renderError` and `renderEmpty` let you replace the entire error/empty state with your own JSX: + +```tsx + ( +
+ ⚠ Sensor unreachable + {error} +
+ )} + renderEmpty={() => β€” no reading yet β€”} +/> +``` + +`renderError` receives the raw error message string; `renderEmpty` takes no arguments. When either is provided, it fully replaces the default `error`/`empty` slot rendering β€” the corresponding `styles.error`/`styles.empty` classes are ignored in that case, since there's no default element left for them to apply to. + +##### Reacting to errors/empty state via `onDataChange` + +`onDataChange` now receives a second argument describing which state just occurred, so you can react to errors or empty data the same way you already react to values: + +```tsx + { + if (meta.kind === "error") { + return { renderError: () => Offline }; + } + if (meta.kind === "empty") { + return { renderEmpty: () => Waiting for first reading… }; + } + if (!data) return; + if (data.value > 80) { + return { title: "High Humidity", theme: "dark" }; + } + }} +/> +``` + +`meta.kind` is one of `"success"`, `"error"`, or `"empty"`; `meta.error` is present only when `meta.kind === "error"`, carrying the underlying error message. + +This is backwards compatible β€” existing `onDataChange={(data) => {...}}` callbacks that ignore the second argument continue to work unchanged. + +--- + #### Formatters export The formatting helpers used internally are also available as a standalone import, for composing into your own `labelText`/`formatValue` functions: diff --git a/src/common.ts b/src/common.ts index 685b5297..ec31ceb8 100644 --- a/src/common.ts +++ b/src/common.ts @@ -63,7 +63,9 @@ export type FormatPreset = export interface FormatOptions { locale?: string; // BCP 47 tag, e.g. "en-IN" β€” defaults to browser locale binary?: boolean; // bytes only: 1024-based (KiB/MiB) vs 1000-based (KB/MB) - precision?: number; // decimal places for the scaled number + /** Decimal places for the scaled number output by a `format` preset. */ + toDecimalPlaces?: number; + } export type FormatResult = { value: string; unit?: string }; diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index 43556543..3ec44fe3 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -2,10 +2,10 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; import { AnedyaWidgetBaseProps, - FormatOptions, - FormatPreset, - LabelFormatPreset, + } from "../common"; + +import type { FormatOptions, FormatPreset, LabelFormatPreset } from "../common"; import { SlotClassNames, WidgetTheme } from "../types/root"; import { @@ -15,13 +15,22 @@ import { } from "../themes/defaultTheme"; import { FORMATTERS, LABEL_FORMATTERS } from "../helpers/formatters"; -export type CardSlot = "container" | "title" | "value" | "unit" | "label"; +export type CardSlot = "container" | "title" | "value" | "unit" | "label"|"error" | "empty"; + + + /** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ export interface CardData { value: number; timestamp: number; } +/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ +export interface CardDataMeta { + kind: "success" | "error" | "empty"; + /** Present only when kind === "error". */ + error?: string; +} export type CardWidgetUpdate = Partial< Omit >; @@ -76,7 +85,7 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * } * }} */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; +onDataChange?: (data: CardData | null, meta: CardDataMeta) => CardWidgetUpdate | void; /** * Named formatting preset for common unit types β€” auto-scales both @@ -89,7 +98,7 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * Ignored if `formatValue` is also provided. */ format?: FormatPreset; - /** Options for the active `format` preset β€” e.g. `{ precision: 2, locale: "en-IN" }`. */ + /** Options for the active `format` preset β€” e.g. `{ formatOptions: 2, locale: "en-IN" }`. */ formatOptions?: FormatOptions; /** * Named preset for the last-updated label's format. Ignored if @@ -97,6 +106,17 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * Defaults to `"time"`, matching the widget's previous fixed behavior. */ labelFormat?: LabelFormatPreset; + /** Custom render for the error state. Return JSX to fully replace the default error text. */ +renderError?: (error: string) => React.ReactNode; + +/** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ +renderEmpty?: () => React.ReactNode; +/** + * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when + * formatting the last-updated label. Defaults to the browser's + * auto-detected timezone if omitted. + */ +timezone?: string; } const DEFAULT_WIDTH = 240; @@ -124,12 +144,15 @@ export function CardWidget({ format, formatOptions, labelFormat, + timezone, + renderError, + renderEmpty, }: CardWidgetProps): React.JSX.Element { const [value, setValue] = useState(null); const [timestamp, setTimestamp] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - + const [isEmpty, setIsEmpty] = useState(false); // Holds the temporary prop overrides returned by onDataChange. // Whenever the callback returns nothing (or the condition no longer // matches), this resets back to {} so the widget falls back to the @@ -139,6 +162,7 @@ export function CardWidget({ const mountedRef = useRef(false); const isFetchingRef = useRef(false); + useEffect(() => { if (!node) return; mountedRef.current = true; @@ -156,14 +180,26 @@ export function CardWidget({ if (res.isSuccess && res.isDataAvailable) { setValue(res.data.value); setTimestamp(res.data.timestamp); - } else { + setError(null); + setIsEmpty(false); + } else if (res.isSuccess && !res.isDataAvailable) { + // Fetch succeeded, but there's genuinely no data yet β€” distinct + // from an actual error. + setValue(null); + setTimestamp(null); + setError(null); + setIsEmpty(true); + } + else { setValue(null); - setError(res.error?.errorMessage ?? "No data available"); + setError(res.error?.errorMessage ?? "Failed to fetch data"); + setIsEmpty(false); } } catch (err: any) { if (!mountedRef.current) return; - setValue(null); + setValue(null); setError(err?.message ?? "Failed to fetch data"); + setIsEmpty(false); } finally { if (mountedRef.current) { setLoading(false); @@ -178,7 +214,7 @@ export function CardWidget({ }; }, [node, variable]); - // Resolve onDataChange whenever the fetched data changes. + // Resolve onDataChange whenever data / error / empty status changes. // The callback returns temporary prop overrides which layer on top // of the widget's original props. useEffect(() => { @@ -189,9 +225,13 @@ export function CardWidget({ const data = value != null && timestamp != null ? { value, timestamp } : null; - - setDynamicProps(onDataChange(data) ?? {}); - }, [value, timestamp, onDataChange]); + const meta: CardDataMeta = error + ? { kind: "error", error } + : isEmpty + ? { kind: "empty" } + : { kind: "success" }; + setDynamicProps(onDataChange(data, meta) ?? {}); + }, [value, timestamp, error, isEmpty, onDataChange]); const resolvedProps = { title, unit, @@ -208,6 +248,9 @@ export function CardWidget({ format, formatOptions, labelFormat, + timezone, + renderError, + renderEmpty, ...dynamicProps, styles: { @@ -239,53 +282,39 @@ export function CardWidget({ ); const { displayValue, displayUnit } = useMemo(() => { - if (value == null) - return { displayValue: null, displayUnit: resolvedProps.unit }; + if (value == null) return { displayValue: null, displayUnit: resolvedProps.unit }; if (resolvedProps.formatValue) { - return { - displayValue: resolvedProps.formatValue(value), - displayUnit: resolvedProps.unit, - }; + return { displayValue: resolvedProps.formatValue(value), displayUnit: resolvedProps.unit }; } if (resolvedProps.format) { - const result = FORMATTERS[resolvedProps.format]( - value, - resolvedProps.formatOptions, - ); + const result = FORMATTERS[resolvedProps.format](value, resolvedProps.formatOptions); return { displayValue: result.value, displayUnit: result.unit }; } if (resolvedProps.decimalPlaces != null) { - return { - displayValue: value.toFixed(resolvedProps.decimalPlaces), - displayUnit: resolvedProps.unit, - }; + return { displayValue: value.toFixed(resolvedProps.decimalPlaces), displayUnit: resolvedProps.unit }; } return { displayValue: String(value), displayUnit: resolvedProps.unit }; - }, [ - value, - resolvedProps.formatValue, - resolvedProps.format, - resolvedProps.formatOptions, - resolvedProps.decimalPlaces, - resolvedProps.unit, - ]); - const displayLabel = useMemo(() => { + }, [value, resolvedProps.formatValue, resolvedProps.format, resolvedProps.formatOptions, resolvedProps.decimalPlaces, resolvedProps.unit]); + + + // Auto-detect the browser's timezone unless the consumer overrides it. + const resolvedTimezone = + resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + const displayLabel = useMemo(() => { if (timestamp == null) return null; if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; - return formatter(timestamp, resolvedProps.formatOptions?.locale); - }, [ - timestamp, - resolvedProps.labelText, - resolvedProps.labelFormat, - resolvedProps.formatOptions?.locale, - ]); + return formatter(timestamp, { + locale: resolvedProps.formatOptions?.locale, + timezone: resolvedTimezone, + }); + }, [timestamp, resolvedProps.labelText, resolvedProps.labelFormat, resolvedProps.formatOptions?.locale, resolvedTimezone]); const hasExplicitHeight = height != null || dynamicProps.height != null; return ( @@ -337,7 +366,17 @@ export function CardWidget({ />
) : error ? ( - {error} + resolvedProps.renderError ? ( + resolvedProps.renderError(error) + ) : ( + {error} + ) + ) :isEmpty ? ( + resolvedProps.renderEmpty ? ( + resolvedProps.renderEmpty() + ) : ( + N/A + ) ) : ( <> Math.abs(raw) >= f) ?? units[units.length - 1]; return { - value: new Intl.NumberFormat(locale, { maximumFractionDigits: precision }).format(raw / factor), + value: new Intl.NumberFormat(locale, { maximumFractionDigits: toDecimalPlaces }).format(raw / factor), unit, }; } @@ -68,8 +68,8 @@ export const FORMATTERS: Record formatBytes(raw, opts), /** Formats a 0–100 number as a percentage string, e.g. 45 -> "45%". */ - percent: (raw, { precision, locale } = {}) => ({ - value: new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: precision ?? 1 }).format(raw / 100), + percent: (raw, { toDecimalPlaces, locale } = {}) => ({ + value: new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: toDecimalPlaces ?? 1 }).format(raw / 100), }), }; @@ -106,27 +106,28 @@ export function relativeTime(timestamp: number, locale?: string): string { return rtf.format(0, "second"); } -export const LABEL_FORMATTERS: Record string> = { - /** Locale time only, e.g. "14:32:10" */ - time: (ts, locale) => { +export const LABEL_FORMATTERS: Record< + LabelFormatPreset, + (ts: number, options?: { locale?: string; timezone?: string }) => string +> = { + time: (ts, options) => { const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); - return `Updated ${d.toLocaleTimeString(locale)}`; + const timeZone = options?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + return `Updated ${d.toLocaleTimeString(options?.locale, { timeZone })}`; }, - /** Locale date only, e.g. "7/24/2026" */ - date: (ts, locale) => { + date: (ts, options) => { const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); - return `Updated ${d.toLocaleDateString(locale)}`; + const timeZone = options?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + return `Updated ${d.toLocaleDateString(options?.locale, { timeZone })}`; }, - /** Locale date + time, e.g. "7/24/2026, 2:32:10 PM" */ - datetime: (ts, locale) => { + datetime: (ts, options) => { const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); - return `Updated ${d.toLocaleString(locale)}`; + const timeZone = options?.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + return `Updated ${d.toLocaleString(options?.locale, { timeZone })}`; }, - /** Human-relative, e.g. "5 minutes ago" */ - relative: (ts, locale) => relativeTime(ts, locale), - /** Raw ISO 8601 string, e.g. "2026-07-24T14:32:10.000Z" β€” useful for logs/debugging */ + relative: (ts, options) => relativeTime(ts, options?.locale), iso: (ts) => { const d = ts < 1e12 ? new Date(ts * 1000) : new Date(ts); - return d.toISOString(); + return d.toISOString(); // always UTC by definition β€” timezone option has no effect here }, }; \ No newline at end of file diff --git a/src/themes/defaultTheme.ts b/src/themes/defaultTheme.ts index da6f9f13..3518b89b 100644 --- a/src/themes/defaultTheme.ts +++ b/src/themes/defaultTheme.ts @@ -15,7 +15,9 @@ unit: label: "text-[length:var(--anedya-card-label-size)]", container: - "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]" + "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]", + error: "text-sm font-medium", + empty: "text-[length:var(--anedya-card-value-size)] font-bold", }; @@ -25,6 +27,8 @@ export const lightTheme: WidgetTheme = { title: "text-slate-500", value: "text-slate-900", label: "text-slate-400", + error: "text-red-600", +empty: "text-slate-400", }, }; @@ -34,6 +38,8 @@ export const darkTheme: WidgetTheme = { title: "text-slate-400", value: "text-white", label: "text-slate-500", + error: "text-red-400", +empty: "text-slate-500", }, }; export const themes = { light: lightTheme, dark: darkTheme } as const; diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index a76992ee..f6fc8342 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -19,6 +19,7 @@ "@babel/core": "^7.29.0", "@eslint/js": "^9.39.4", "@rolldown/plugin-babel": "^0.2.1", + "@tailwindcss/vite": "^4.3.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", @@ -27,6 +28,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.4.0", + "tailwindcss": "^4.3.3", "vite": "^8.0.1" } }, @@ -307,7 +309,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" @@ -320,7 +321,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -1314,6 +1314,539 @@ "dev": true, "license": "MIT" }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", + "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "tailwindcss": "4.3.3" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", @@ -1745,6 +2278,20 @@ "dev": true, "license": "ISC" }, + "node_modules/enhanced-resolve": { + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -2125,6 +2672,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2266,6 +2820,16 @@ "dev": true, "license": "ISC" }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2683,6 +3247,16 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -3161,6 +3735,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", diff --git a/test/my-app/package.json b/test/my-app/package.json index bc311916..69feefbc 100644 --- a/test/my-app/package.json +++ b/test/my-app/package.json @@ -13,14 +13,15 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^9.2.0", + "public-widget-sdk": "file:../../", "react": "^19.2.4", - "react-dom": "^19.2.4", - "public-widget-sdk": "file:../../" + "react-dom": "^19.2.4" }, "devDependencies": { "@babel/core": "^7.29.0", "@eslint/js": "^9.39.4", "@rolldown/plugin-babel": "^0.2.1", + "@tailwindcss/vite": "^4.3.3", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", @@ -29,6 +30,7 @@ "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.5.2", "globals": "^17.4.0", + "tailwindcss": "^4.3.3", "vite": "^8.0.1" } } diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 55d8b8ab..c09709a4 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -9,8 +9,12 @@ import { CardWidget } from "public-widget-sdk"; // Import your stylesheet via the industry-standard subpath import "public-widget-sdk/styles.css"; import { relativeTime } from "public-widget-sdk/formatters"; - - +import "./index.css"; +// This demo has its own Tailwind build (see vite.config.js + src/index.css), +// specifically to test consumer-side class overrides via `className`/`styles`. +// A real consumer app needs the same setup β€” the widget package's own +// precompiled stylesheet only covers its built-in default classes, not +// arbitrary classes a consumer passes in. const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; @@ -47,7 +51,16 @@ export default function App() { * formatting props. Every fallback in the widget in one place. * ============================================================ */} `Last synced ${relativeTime(ts)}`} + // timezone="Asia/Kolkata" +// timezone="America/Los_Angeles" + onDataChange={(data, meta) => { + if (meta.kind === "error") { + return { renderError: () => Sensor unreachable }; + } + if (meta.kind === "empty") { + return { renderEmpty: () => β€” no reading yet β€” }; + } + }} /> @@ -85,11 +98,16 @@ export default function App() { title="styles vs className" unit="%" decimalPlaces={1} - className="shadow-lg" // <- outer box only, ordinary React convention + className="shadow-lg bg-blue-50 border-blue-300" // <- outer box only, ordinary React convention + // styles={{ + // value: "text-red-500 text-5xl", // <- targets the INNER "value" slot specifically + // title: "uppercase tracking-wider", // <- targets the INNER "title" slot specifically + // }} styles={{ - value: "text-red-500 text-5xl", // <- targets the INNER "value" slot specifically - title: "uppercase tracking-wider", // <- targets the INNER "title" slot specifically - }} + container: "bg-blue-50 border-blue-300", // background/border of the card itself + value: "text-red-500 text-5xl", + title: "uppercase tracking-wider text-blue-700", // added color here +}} /> diff --git a/test/my-app/src/index.css b/test/my-app/src/index.css index 2c84af06..393a406c 100644 --- a/test/my-app/src/index.css +++ b/test/my-app/src/index.css @@ -1,3 +1,5 @@ +@import "tailwindcss"; + :root { --text: #6b6375; --text-h: #08060d; diff --git a/test/my-app/vite.config.js b/test/my-app/vite.config.js index 1543c923..65fb8852 100644 --- a/test/my-app/vite.config.js +++ b/test/my-app/vite.config.js @@ -1,12 +1,14 @@ import { defineConfig } from 'vite' import react, { reactCompilerPreset } from '@vitejs/plugin-react' import babel from '@rolldown/plugin-babel' +import tailwindcss from "@tailwindcss/vite"; // https://vite.dev/config/ export default defineConfig({ plugins: [ react(), - babel({ presets: [reactCompilerPreset()] }) + babel({ presets: [reactCompilerPreset()] }), + tailwindcss() ], resolve: { dedupe: ["react", "react-dom", "@base-ui/react"], From 82b35ec3e6e33fd59f3d312257b92517949bbfda Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 11:10:40 +0530 Subject: [PATCH 43/66] check & test gauge props --- .../GaugeChart/GaugeChartWidget.tsx | 71 ++-- src/themes/gaugeTheme.ts | 2 +- test/my-app/src/App.jsx | 329 ++++++++---------- 3 files changed, 178 insertions(+), 224 deletions(-) diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index 8277506c..53eebb3e 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -18,7 +18,7 @@ import { GaugeSlot, GaugeTickConfig, // NEW GaugeTrackConfig, - GaugeValueLabelConfig, + // GaugeValueLabelConfig, GaugeEasing, } from "../../types/gauge"; import { @@ -52,7 +52,7 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { color?: GaugeColor; needle?: GaugeNeedleConfig; - valueLabel?: GaugeValueLabelConfig; + // valueLabel?: GaugeValueLabelConfig; /** REQUIREMENT 3/4: radial min/max tick marks drawn around the arc. */ tick?: GaugeTickConfig; animation?: GaugeAnimationConfig; @@ -271,19 +271,19 @@ export function GaugeWidget({ track, color, needle, - valueLabel, + // valueLabel, tick, animation, unit, decimalPlaces, - formatValue, format, formatOptions, + formatValue, labelText, labelFormat, styles = {}, onDataChange, - // onClick, + }: GaugeWidgetProps) { const svgRef = useRef(null); // REQUIREMENT 2: stable "now" fallback for manual/custom `value` mode, @@ -377,7 +377,8 @@ export function GaugeWidget({ const resolvedProps = { title, theme, - className, + min, + max, width, height, minWidth, @@ -385,19 +386,16 @@ export function GaugeWidget({ minHeight, maxHeight, aspectRatio, - min, - max, size, - responsive, arc, track, color, needle, - valueLabel, - tick, animation, + tick, unit, decimalPlaces, + className, formatValue, format, formatOptions, @@ -405,6 +403,8 @@ export function GaugeWidget({ labelFormat, ...dynamicProps, styles: mergedStyles, + responsive, // not work + }; // ---- Resolved config ---- @@ -435,9 +435,9 @@ export function GaugeWidget({ animation: resolvedProps.needle?.animation ?? true, }; - const resolvedValueLabel: Required> = { - show: resolvedProps.valueLabel?.show ?? true, - }; + // const resolvedValueLabel: Required> = { + // show: resolvedProps.valueLabel?.show ?? true, + // }; const resolvedAnimation = { ...DEFAULT_ANIMATION, @@ -470,15 +470,15 @@ export function GaugeWidget({ ? gaugeLightTheme : (resolvedProps.theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; - const resolveSlot = useCallback( - (slot: GaugeSlot) => - twMerge( - GAUGE_DEFAULT_CLASSES[slot], - resolvedTheme.styles[slot], - resolvedProps.styles[slot] - ), - [resolvedTheme, resolvedProps.styles] - ); + const resolveSlot = useCallback( + (slot: GaugeSlot) => + twMerge( + GAUGE_DEFAULT_CLASSES[slot], + resolvedTheme?.styles?.[slot], + resolvedProps.styles[slot] + ), + [resolvedTheme, resolvedProps.styles] + ); // ---- REQUIREMENT 3: tick values (min..max split into `count` even steps) ---- const tickValues = useMemo(() => { @@ -912,20 +912,17 @@ export function GaugeWidget({ // (no-needle / donut mode) without duplicating JSX. const valueBlock = ( <> - {resolvedValueLabel.show && ( - - {displayValue} - {displayUnit && ( - {displayUnit} - )} - - )} - + + {displayValue} + {displayUnit && ( + {displayUnit} + )} + {displayLabel && ( {displayLabel} )} diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index 8ea9c7ed..cad924cc 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -27,12 +27,12 @@ export const gaugeLightTheme: WidgetTheme = { container: "", title: "text-slate-500", unit: "text-slate-500", + label: "text-slate-400", track: "text-slate-200", // read via `currentColor` on the track path bar: "text-indigo-500", needle: "text-slate-700", needleCap: "text-slate-700", value: "text-slate-900", - label: "text-slate-400", tick: "text-slate-300", tickLabel: "text-slate-400", }, diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 2164dfab..dd09c37f 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -21,7 +21,7 @@ const node = anedya.newNode(client, nodeId); * built-in default β€” anything omitted falls back to lightTheme/darkTheme. */ const emeraldTheme = { - classNames: { + styles: { container: "bg-emerald-50 border-emerald-200", title: "text-emerald-700", value: "text-emerald-900", @@ -29,6 +29,38 @@ const emeraldTheme = { }, }; +export const gaugeCustomLightTheme = { + styles: { + // Tailwind classes for HTML container and text wrappers + container: "bg-emerald-50 border-emerald-200", + title: "text-emerald-800", + value: "text-emerald-950", + label: "text-emerald-600", + + // Hex colors for D3 SVG elements + track: "#E2E8F0", // Soft gray background arc (slate-200) + bar: "#10B981", // Primary value fill (emerald-500) + needle: "#047857", // Darker accent needle for high visibility (emerald-700) + needleCap: "#065F46", // Needle center cap (emerald-800) + }, +}; + +export const gaugeCustomDarkTheme = { + styles: { + // Tailwind classes for HTML container and text wrappers + container: "bg-yellow-500 border-emerald-800/50 backdrop-blur-sm", + title: "text-red-500", + value: "text-yellow-500", + label: "text-red-500", + + // Hex colors for D3 SVG elements + track: "text-red-500", // Dark muted background arc (slate-800) + bar: "text-yellow-500", // High-contrast bright fill (emerald-400) + needle: "text-red-500", // Bright needle for dark mode contrast (emerald-300) + needleCap: "text-yellow-500", // Bright needle center cap (emerald-200) + }, +}; + const commonProps = { node, variable: "humidity" }; export default function App() { @@ -178,184 +210,7 @@ export default function App() { * whole styles/theme system. * ============================================================ */} {/* */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - alert(`Clicked ${v}`)} - /> - {/* */} - {/* */} - - `Last seen: ${new Date(ts).toLocaleTimeString()}`} - /> - `⭐ ${Math.round(v)}%`} // your own text - unit="" // hide unit - labelText={(ts) => `recorded ${new Date(ts).toLocaleString()}`} - timestamp={Date.now() - 86400000} // 1 day ago - onClick={(v) => console.log("Clicked", v)} - /> + */} - {/*

Testing All Gauge Widget Props

+

Testing All Gauge Widget Props

+ + + `Hello ${v} km/h`} + // labelFormat="relative" + // labelFormat="date" + labelText={(ts) => `Refreshed at ${new Date(ts).toLocaleTimeString()}`} // format="bytes" + // formatOptions={{"binary":true,"precision":2}} + + // value={1234567.891} + // format="number" + // formatOptions={{"locale":"de-DE","precision":2}} + /> - - - */} - + container: + "bg-slate-900 rounded-2xl border border-slate-700 shadow-lg", + title: "text-slate-300 uppercase tracking-wide text-xs", + unit: "text-red-500 text-sm font-normal", + value: "text-white text-4xl font-black", + label: "text-slate-500 text-[11px] italic", + track: "text-yellow-500", + bar: "text-emerald-400", + needle: "text-red-500", + needleCap: "text-yellow-500", + tick: "text-slate-700", + tickLabel: "text-slate-500 text-[9px]", + }} + /> + + { + if (!data) { + return { + title: "No Data", + color: "#6b7280", + styles: { value: "text-slate-500" }, + }; + } + + const isCritical = data.value > 70; + const isWarning = data.value > 40 && data.value <= 60; + + return { + // top-level scalar/config overrides + title: isCritical ? "Critical" : isWarning ? "Warning" : "Normal", + color: isCritical ? "#ef4444" : isWarning ? "#f59e0b" : "#10b981", + unit: "Β°C", + formatValue: (v) => `${v.toFixed(1)}`, + labelText: (ts) => `Sampled ${new Date(ts).toLocaleTimeString()}`, + needle: { needleColor: isCritical ? "#ef4444" : "#10b981" }, + track: { color: isCritical ? "#450a0a" : "#052e2b" }, + animation: { duration: isCritical ? 400 : 1000 }, + + // per-slot class overrides β€” merges with (doesn't replace) the static `styles` prop + styles: { + value: isCritical ? "text-red-500 animate-pulse" : "text-black", + title: isCritical ? "text-red-400" : "text-slate-400", + }, + }; + }} + /> +
); } From 482cb0456e2b48d9792f99b5dc67044bc233461c Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 11:33:57 +0530 Subject: [PATCH 44/66] commit --- test/my-app/src/App.jsx | 65 ++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 14a642e7..956663c5 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -4,7 +4,7 @@ import { CardWidget } from "../../../src"; import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; import "public-widget-sdk/styles.css"; import { relativeTime } from "public-widget-sdk/formatters"; -import "./index.css"; +import "./index.css"; // This demo has its own Tailwind build (see vite.config.js + src/index.css), // specifically to test consumer-side class overrides via `className`/`styles`. // A real consumer app needs the same setup β€” the widget package's own @@ -16,10 +16,6 @@ const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; import { relativeTime } from "../../../src/helpers/formatters"; -const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -const token = - "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; -const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); @@ -76,26 +72,45 @@ const commonProps = { node, variable: "humidity" }; export default function App() { return ( -
+
{/* ============================================================ * 1. Default appearance β€” no theme, no styles, no * formatting props. Every fallback in the widget in one place. * ============================================================ */} - { - if (meta.kind === "error") { - return { renderError: () => Sensor unreachable }; - } - if (meta.kind === "empty") { - return { renderEmpty: () => β€” no reading yet β€” }; - } - }} - - /> - + if (meta.kind === "error") { + return { + renderError: () => ( + + Sensor unreachable + + ), + }; + } + if (meta.kind === "empty") { + return { + renderEmpty: () => ( + β€” no reading yet β€” + ), + }; + } + }} + /> {/* ============================================================ * 2. theme β€” a reusable, shareable WidgetTheme object. Same @@ -146,11 +161,10 @@ export default function App() { // title: "uppercase tracking-wider", // <- targets the INNER "title" slot specifically // }} styles={{ - container: "bg-blue-50 border-blue-300", // background/border of the card itself - value: "text-red-500 text-5xl", - title: "uppercase tracking-wider text-blue-700", // added color here -}} - + container: "bg-blue-50 border-blue-300", // background/border of the card itself + value: "text-red-500 text-5xl", + title: "uppercase tracking-wider text-blue-700", // added color here + }} /> {/* ============================================================ * 4. Plain CSS classes β€” styles works with ANY class source, @@ -398,7 +412,6 @@ export default function App() { }; }} /> -
); } From b257d99a8d990fc22bbb805738e359912ea7fabf Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 11:37:24 +0530 Subject: [PATCH 45/66] run : npm i & npm run build --- dist/index.d.mts | 26 ++++++++++++++++++----- package-lock.json | 40 ++++++++++++++++++++++++++++++++--- test/my-app/package-lock.json | 23 -------------------- test/my-app/src/App.jsx | 2 -- 4 files changed, 58 insertions(+), 33 deletions(-) diff --git a/dist/index.d.mts b/dist/index.d.mts index 77e68b7e..f4fd538d 100644 --- a/dist/index.d.mts +++ b/dist/index.d.mts @@ -1,11 +1,17 @@ -import { a as LabelFormatPreset, n as FormatOptions, o as SlotClassNames, r as FormatPreset, t as AnedyaWidgetBaseProps } from "./common-DARTvNue.mjs"; +import { a as LabelFormatPreset, n as FormatOptions, o as SlotClassNames, r as FormatPreset, t as AnedyaWidgetBaseProps } from "./common-DoLkuLwh.mjs"; //#region src/components/CardWidget.d.ts -type CardSlot = "container" | "title" | "value" | "unit" | "label"; +type CardSlot = "container" | "title" | "value" | "unit" | "label" | "error" | "empty"; /** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ interface CardData { value: number; timestamp: number; } +/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ +interface CardDataMeta { + kind: "success" | "error" | "empty"; + /** Present only when kind === "error". */ + error?: string; +} type CardWidgetUpdate = Partial>; interface CardWidgetProps extends AnedyaWidgetBaseProps { unit?: string; @@ -57,7 +63,7 @@ interface CardWidgetProps extends AnedyaWidgetBaseProps { * } * }} */ - onDataChange?: (data: CardData | null) => CardWidgetUpdate | void; + onDataChange?: (data: CardData | null, meta: CardDataMeta) => CardWidgetUpdate | void; /** * Named formatting preset for common unit types β€” auto-scales both * the displayed number and its unit (e.g. `"bytes"` turns `500000` @@ -69,7 +75,7 @@ interface CardWidgetProps extends AnedyaWidgetBaseProps { * Ignored if `formatValue` is also provided. */ format?: FormatPreset; - /** Options for the active `format` preset β€” e.g. `{ precision: 2, locale: "en-IN" }`. */ + /** Options for the active `format` preset β€” e.g. `{ formatOptions: 2, locale: "en-IN" }`. */ formatOptions?: FormatOptions; /** * Named preset for the last-updated label's format. Ignored if @@ -77,7 +83,17 @@ interface CardWidgetProps extends AnedyaWidgetBaseProps { * Defaults to `"time"`, matching the widget's previous fixed behavior. */ labelFormat?: LabelFormatPreset; + /** Custom render for the error state. Return JSX to fully replace the default error text. */ + renderError?: (error: string) => React.ReactNode; + /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ + renderEmpty?: () => React.ReactNode; + /** + * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when + * formatting the last-updated label. Defaults to the browser's + * auto-detected timezone if omitted. + */ + timezone?: string; } -declare function CardWidget({ node, variable, title, unit, decimalPlaces, formatValue, labelText, styles, onDataChange, theme, className, width, height, minWidth, maxWidth, format, formatOptions, labelFormat }: CardWidgetProps): React.JSX.Element; +declare function CardWidget({ node, variable, title, unit, decimalPlaces, formatValue, labelText, styles, onDataChange, theme, className, width, height, minWidth, maxWidth, format, formatOptions, labelFormat, timezone, renderError, renderEmpty }: CardWidgetProps): React.JSX.Element; //#endregion export { CardWidget }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e1887761..79187fe5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -192,9 +192,9 @@ ] }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", "dev": true, "license": "MIT", "optional": true, @@ -868,6 +868,40 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@rolldown/binding-win32-arm64-msvc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json index c6fa7824..53d391c0 100644 --- a/test/my-app/package-lock.json +++ b/test/my-app/package-lock.json @@ -300,29 +300,6 @@ "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", - "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 956663c5..209c2233 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -15,8 +15,6 @@ const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; -import { relativeTime } from "../../../src/helpers/formatters"; - const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); const client = anedya.newClient(config); From a806f996875bb913f6d72ac45c8e839608caffe1 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 12:34:59 +0530 Subject: [PATCH 46/66] renderError, renderEmpty are added for custom handling, and timezone is added for user to pass thier choosen timezone in Gauge Widget as well --- src/components/CardWidget.tsx | 118 +++++++++++------- .../GaugeChart/GaugeChartWidget.tsx | 101 ++++++++++++--- src/themes/defaultTheme.ts | 25 ++-- src/themes/gaugeTheme.ts | 13 +- src/types/gauge.ts | 4 +- test/my-app/src/App.jsx | 38 +++++- 6 files changed, 211 insertions(+), 88 deletions(-) diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx index fc9bd83b..942d4596 100644 --- a/src/components/CardWidget.tsx +++ b/src/components/CardWidget.tsx @@ -1,9 +1,6 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; -import { - AnedyaWidgetBaseProps, - -} from "../common"; +import { AnedyaWidgetBaseProps } from "../common"; import type { FormatOptions, FormatPreset, LabelFormatPreset } from "../common"; import { SlotClassNames, WidgetTheme } from "../types/root"; @@ -15,10 +12,14 @@ import { } from "../themes/defaultTheme"; import { FORMATTERS, LABEL_FORMATTERS } from "../helpers/formatters"; -export type CardSlot = "container" | "title" | "value" | "unit" | "label"|"error" | "empty"; - - - +export type CardSlot = + | "container" + | "title" + | "value" + | "unit" + | "label" + | "error" + | "empty"; /** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ export interface CardData { @@ -85,7 +86,10 @@ export interface CardWidgetProps extends AnedyaWidgetBaseProps { * } * }} */ -onDataChange?: (data: CardData | null, meta: CardDataMeta) => CardWidgetUpdate | void; + onDataChange?: ( + data: CardData | null, + meta: CardDataMeta + ) => CardWidgetUpdate | void; /** * Named formatting preset for common unit types β€” auto-scales both @@ -107,16 +111,16 @@ onDataChange?: (data: CardData | null, meta: CardDataMeta) => CardWidgetUpdate | */ labelFormat?: LabelFormatPreset; /** Custom render for the error state. Return JSX to fully replace the default error text. */ -renderError?: (error: string) => React.ReactNode; - -/** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ -renderEmpty?: () => React.ReactNode; -/** - * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when - * formatting the last-updated label. Defaults to the browser's - * auto-detected timezone if omitted. - */ -timezone?: string; + renderError?: (error: string) => React.ReactNode; + + /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ + renderEmpty?: () => React.ReactNode; + /** + * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when + * formatting the last-updated label. Defaults to the browser's + * auto-detected timezone if omitted. + */ + timezone?: string; } const DEFAULT_WIDTH = 240; @@ -144,7 +148,7 @@ export function CardWidget({ format, formatOptions, labelFormat, - timezone, + timezone, renderError, renderEmpty, }: CardWidgetProps): React.JSX.Element { @@ -162,7 +166,6 @@ export function CardWidget({ const mountedRef = useRef(false); const isFetchingRef = useRef(false); - useEffect(() => { if (!node) return; mountedRef.current = true; @@ -182,22 +185,21 @@ export function CardWidget({ setTimestamp(res.data.timestamp); setError(null); setIsEmpty(false); - } else if (res.isSuccess && !res.isDataAvailable) { + } else if (res.isSuccess && !res.isDataAvailable) { // Fetch succeeded, but there's genuinely no data yet β€” distinct // from an actual error. setValue(null); setTimestamp(null); setError(null); setIsEmpty(true); - } - else { + } else { setValue(null); setError(res.error?.errorMessage ?? "Failed to fetch data"); setIsEmpty(false); } } catch (err: any) { if (!mountedRef.current) return; - setValue(null); + setValue(null); setError(err?.message ?? "Failed to fetch data"); setIsEmpty(false); } finally { @@ -214,7 +216,7 @@ export function CardWidget({ }; }, [node, variable]); - // Resolve onDataChange whenever data / error / empty status changes. + // Resolve onDataChange whenever data / error / empty status changes. // The callback returns temporary prop overrides which layer on top // of the widget's original props. useEffect(() => { @@ -225,11 +227,11 @@ export function CardWidget({ const data = value != null && timestamp != null ? { value, timestamp } : null; - const meta: CardDataMeta = error + const meta: CardDataMeta = error ? { kind: "error", error } : isEmpty - ? { kind: "empty" } - : { kind: "success" }; + ? { kind: "empty" } + : { kind: "success" }; setDynamicProps(onDataChange(data, meta) ?? {}); }, [value, timestamp, error, isEmpty, onDataChange]); const resolvedProps = { @@ -248,7 +250,7 @@ export function CardWidget({ format, formatOptions, labelFormat, - timezone, + timezone, renderError, renderEmpty, ...dynamicProps, @@ -263,8 +265,8 @@ export function CardWidget({ resolvedProps.theme === "dark" ? darkTheme : resolvedProps.theme === "light" - ? lightTheme - : (resolvedProps.theme ?? lightTheme); + ? lightTheme + : resolvedProps.theme ?? lightTheme; // Per-slot resolution, lowest to highest precedence: // 1. CARD_DEFAULT_CLASSES[slot] β€” built-in baseline @@ -278,33 +280,49 @@ export function CardWidget({ twMerge( CARD_DEFAULT_CLASSES[slot], resolvedTheme.styles?.[slot], - resolvedProps.styles?.[slot], + resolvedProps.styles?.[slot] ); const { displayValue, displayUnit } = useMemo(() => { - if (value == null) return { displayValue: null, displayUnit: resolvedProps.unit }; + if (value == null) + return { displayValue: null, displayUnit: resolvedProps.unit }; if (resolvedProps.formatValue) { - return { displayValue: resolvedProps.formatValue(value), displayUnit: resolvedProps.unit }; + return { + displayValue: resolvedProps.formatValue(value), + displayUnit: resolvedProps.unit, + }; } if (resolvedProps.format) { - const result = FORMATTERS[resolvedProps.format](value, resolvedProps.formatOptions); + const result = FORMATTERS[resolvedProps.format]( + value, + resolvedProps.formatOptions + ); return { displayValue: result.value, displayUnit: result.unit }; } if (resolvedProps.decimalPlaces != null) { - return { displayValue: value.toFixed(resolvedProps.decimalPlaces), displayUnit: resolvedProps.unit }; + return { + displayValue: value.toFixed(resolvedProps.decimalPlaces), + displayUnit: resolvedProps.unit, + }; } return { displayValue: String(value), displayUnit: resolvedProps.unit }; - }, [value, resolvedProps.formatValue, resolvedProps.format, resolvedProps.formatOptions, resolvedProps.decimalPlaces, resolvedProps.unit]); - - - // Auto-detect the browser's timezone unless the consumer overrides it. + }, [ + value, + resolvedProps.formatValue, + resolvedProps.format, + resolvedProps.formatOptions, + resolvedProps.decimalPlaces, + resolvedProps.unit, + ]); + + // Auto-detect the browser's timezone unless the consumer overrides it. const resolvedTimezone = resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; - const displayLabel = useMemo(() => { + const displayLabel = useMemo(() => { if (timestamp == null) return null; if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); @@ -314,7 +332,13 @@ export function CardWidget({ locale: resolvedProps.formatOptions?.locale, timezone: resolvedTimezone, }); - }, [timestamp, resolvedProps.labelText, resolvedProps.labelFormat, resolvedProps.formatOptions?.locale, resolvedTimezone]); + }, [ + timestamp, + resolvedProps.labelText, + resolvedProps.labelFormat, + resolvedProps.formatOptions?.locale, + resolvedTimezone, + ]); const hasExplicitHeight = height != null || dynamicProps.height != null; return ( @@ -336,7 +360,7 @@ export function CardWidget({ className={twMerge( "anedya-card", resolveSlot("container"), - resolvedProps.className, + resolvedProps.className )} style={{ flex: "1 0 auto", @@ -371,7 +395,7 @@ export function CardWidget({ ) : ( {error} ) - ) :isEmpty ? ( + ) : isEmpty ? ( resolvedProps.renderEmpty ? ( resolvedProps.renderEmpty() ) : ( @@ -382,7 +406,7 @@ export function CardWidget({ {displayValue} @@ -399,4 +423,4 @@ export function CardWidget({
); -} \ No newline at end of file +} diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index 53eebb3e..8ff8cd8d 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -36,6 +36,13 @@ export interface GaugeData { timestamp: number; } +/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ +export interface GaugeDataMeta { + kind: "success" | "error" | "empty"; + /** Present only when kind === "error". */ + error?: string; +} + export type GaugeWidgetUpdate = Partial< Omit >; @@ -65,15 +72,30 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { formatOptions?: FormatOptions; labelText?: (timestamp: number) => string; labelFormat?: LabelFormatPreset; + /** + * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when + * formatting the last-updated label. Defaults to the browser's + * auto-detected timezone if omitted. + */ + timezone?: string; styles?: SlotClassNames; - style?: React.CSSProperties; + // style?: React.CSSProperties; onClick?: (value: number) => void; // REQUIREMENT 5: onValueChange removed β€” onDataChange already lets the // caller override *any* prop whenever new data arrives, so a separate // value-only callback was redundant. - onDataChange?: (data: GaugeData | null) => GaugeWidgetUpdate | void; + onDataChange?: ( + data: GaugeData | null, + meta: GaugeDataMeta + ) => GaugeWidgetUpdate | void; + + /** Custom render for the error state. Return JSX to fully replace the default error text. */ + renderError?: (error: string) => React.ReactNode; + + /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ + renderEmpty?: () => React.ReactNode; } const DEG2RAD = Math.PI / 180; @@ -254,7 +276,7 @@ export function GaugeWidget({ title = "Latest Value", theme, className, - style, + // style, width, height, minWidth = 160, @@ -281,9 +303,11 @@ export function GaugeWidget({ formatValue, labelText, labelFormat, + timezone, styles = {}, onDataChange, - + renderError, + renderEmpty, }: GaugeWidgetProps) { const svgRef = useRef(null); // REQUIREMENT 2: stable "now" fallback for manual/custom `value` mode, @@ -294,6 +318,7 @@ export function GaugeWidget({ const [timestamp, setTimestamp] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); + const [isEmpty, setIsEmpty] = useState(false); const [dynamicProps, setDynamicProps] = useState({}); @@ -318,14 +343,25 @@ export function GaugeWidget({ if (res.isSuccess && res.isDataAvailable) { setFetchedValue(res.data.value); setTimestamp(res.data.timestamp); + setError(null); + setIsEmpty(false); + } else if (res.isSuccess && !res.isDataAvailable) { + // Fetch succeeded, but there's genuinely no data yet β€” distinct + // from an actual error. + setFetchedValue(null); + setTimestamp(null); + setError(null); + setIsEmpty(true); } else { setFetchedValue(null); setError(res.error?.errorMessage ?? "No data available"); + setIsEmpty(false); } } catch (err: any) { if (!mountedRef.current) return; setFetchedValue(null); setError(err?.message ?? "Failed to fetch data"); + setIsEmpty(false); } finally { if (mountedRef.current) { setLoading(false); @@ -351,9 +387,14 @@ export function GaugeWidget({ fetchedValue != null && timestamp != null ? { value: fetchedValue, timestamp } : null; + const meta: GaugeDataMeta = error + ? { kind: "error", error } + : isEmpty + ? { kind: "empty" } + : { kind: "success" }; - setDynamicProps(onDataChange(data) ?? {}); - }, [fetchedValue, timestamp, onDataChange]); + setDynamicProps(onDataChange(data, meta) ?? {}); + }, [fetchedValue, timestamp, error, isEmpty, onDataChange]); const rawValue = fetchedValue ?? valueProp ?? min; const clampedValue = Math.min(max, Math.max(min, rawValue)); @@ -401,10 +442,12 @@ export function GaugeWidget({ formatOptions, labelText, labelFormat, + timezone, + renderError, + renderEmpty, ...dynamicProps, styles: mergedStyles, responsive, // not work - }; // ---- Resolved config ---- @@ -470,15 +513,15 @@ export function GaugeWidget({ ? gaugeLightTheme : (resolvedProps.theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; - const resolveSlot = useCallback( - (slot: GaugeSlot) => - twMerge( - GAUGE_DEFAULT_CLASSES[slot], - resolvedTheme?.styles?.[slot], - resolvedProps.styles[slot] - ), - [resolvedTheme, resolvedProps.styles] - ); + const resolveSlot = useCallback( + (slot: GaugeSlot) => + twMerge( + GAUGE_DEFAULT_CLASSES[slot], + resolvedTheme?.styles?.[slot], + resolvedProps.styles[slot] + ), + [resolvedTheme, resolvedProps.styles] + ); // ---- REQUIREMENT 3: tick values (min..max split into `count` even steps) ---- const tickValues = useMemo(() => { @@ -559,6 +602,10 @@ export function GaugeWidget({ [timestamp, valueProp] ); + // Auto-detect the browser's timezone unless the consumer overrides it. + const resolvedTimezone = + resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + // ---- Last-updated label β€” THIS is what shows the time ---- const displayLabel = useMemo(() => { if (effectiveTimestamp == null) return null; @@ -567,12 +614,16 @@ export function GaugeWidget({ return resolvedProps.labelText(effectiveTimestamp); const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; - return formatter(effectiveTimestamp, resolvedProps.formatOptions?.locale); + return formatter(effectiveTimestamp, { + locale: resolvedProps.formatOptions?.locale, + timezone: resolvedTimezone, + } as any); }, [ effectiveTimestamp, resolvedProps.labelText, resolvedProps.labelFormat, resolvedProps.formatOptions?.locale, + resolvedTimezone, ]); // ---- Geometry ---- @@ -948,7 +999,7 @@ export function GaugeWidget({ ? undefined : resolvedProps.aspectRatio ?? 1 / DEFAULT_HEIGHT_RATIO, boxSizing: "border-box", - ...style, + // ...style, }} // onClick={handleClick} > @@ -1010,7 +1061,7 @@ export function GaugeWidget({ value/label directly over the arc's visual center (cx, cy). Position is expressed as a % of the viewBox so it stays correct at any container size. */} - {!resolvedNeedle.show && !loading && !error && ( + {!resolvedNeedle.show && !loading && !error && !isEmpty && (
) : error ? ( - {error} + resolvedProps.renderError ? ( + resolvedProps.renderError(error) + ) : ( + {error} + ) + ) : isEmpty ? ( + resolvedProps.renderEmpty ? ( + resolvedProps.renderEmpty() + ) : ( + N/A + ) ) : ( // REQUIREMENT 1: needle-mode keeps the original below-the-arc // layout. No-needle mode already rendered `valueBlock` centered above. diff --git a/src/themes/defaultTheme.ts b/src/themes/defaultTheme.ts index 3518b89b..e2f0a505 100644 --- a/src/themes/defaultTheme.ts +++ b/src/themes/defaultTheme.ts @@ -1,26 +1,21 @@ import { CardSlot } from "../components/CardWidget"; import { WidgetTheme } from "../types/root"; - export const CARD_DEFAULT_CLASSES: Record = { + title: "text-[length:var(--anedya-card-title-size)] font-medium", - title: - "text-[length:var(--anedya-card-title-size)] font-medium", - -value: "text-[length:var(--anedya-card-value-size)] font-bold max-w-full min-w-0 leading-tight", + value: + "text-[length:var(--anedya-card-value-size)] font-bold max-w-full min-w-0 leading-tight", -unit: - "text-[length:var(--anedya-card-unit-size)]", + unit: "text-[length:var(--anedya-card-unit-size)]", -label: - "text-[length:var(--anedya-card-label-size)]", -container: - "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]", + label: "text-[length:var(--anedya-card-label-size)]", + container: + "flex flex-col items-center justify-center text-center border rounded-xl p-[var(--anedya-card-padding)] gap-[var(--anedya-card-gap)]", error: "text-sm font-medium", empty: "text-[length:var(--anedya-card-value-size)] font-bold", }; - export const lightTheme: WidgetTheme = { styles: { container: "bg-white border-slate-200", @@ -28,7 +23,7 @@ export const lightTheme: WidgetTheme = { value: "text-slate-900", label: "text-slate-400", error: "text-red-600", -empty: "text-slate-400", + empty: "text-slate-400", }, }; @@ -39,9 +34,9 @@ export const darkTheme: WidgetTheme = { value: "text-white", label: "text-slate-500", error: "text-red-400", -empty: "text-slate-500", + empty: "text-slate-500", }, }; export const themes = { light: lightTheme, dark: darkTheme } as const; export type ThemeName = keyof typeof themes; -export const DEFAULT_THEME: ThemeName = "light"; \ No newline at end of file +export const DEFAULT_THEME: ThemeName = "light"; diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index cad924cc..486ac3bc 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -20,6 +20,8 @@ export const GAUGE_DEFAULT_CLASSES: Record = { // inline style in the widget, which wins over classes), so this only // needs non-size utilities. tickLabel: "font-medium select-none", + error: "text-sm font-medium", + empty: "text-[length:var(--anedya-card-value-size)] font-bold", }; export const gaugeLightTheme: WidgetTheme = { @@ -35,6 +37,8 @@ export const gaugeLightTheme: WidgetTheme = { value: "text-slate-900", tick: "text-slate-300", tickLabel: "text-slate-400", + error: "text-red-600", + empty: "text-slate-400", }, }; @@ -51,8 +55,13 @@ export const gaugeDarkTheme: WidgetTheme = { label: "text-slate-500", tick: "text-slate-600", tickLabel: "text-slate-500", + error: "text-red-400", + empty: "text-slate-500", }, }; -export const gaugeThemes = { light: gaugeLightTheme, dark: gaugeDarkTheme } as const; -export const DEFAULT_GAUGE_THEME = gaugeLightTheme; \ No newline at end of file +export const gaugeThemes = { + light: gaugeLightTheme, + dark: gaugeDarkTheme, +} as const; +export const DEFAULT_GAUGE_THEME = gaugeLightTheme; diff --git a/src/types/gauge.ts b/src/types/gauge.ts index 5adbbaf8..018d1373 100644 --- a/src/types/gauge.ts +++ b/src/types/gauge.ts @@ -11,7 +11,9 @@ export type GaugeSlot = | "value" | "label" | "tick" // NEW β€” tick line styling via `styles` prop - | "tickLabel"; // NEW β€” tick number styling via `styles` prop + | "tickLabel" // NEW β€” tick number styling via `styles` prop + | "error" + | "empty"; export interface GaugeArcConfig { /** Degrees, 0 = 12 o'clock, clockwise-positive. */ diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 209c2233..8e498efa 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -272,7 +272,7 @@ export default function App() { {/* + + ( +
+ ⚠ Sensor unreachable + {error} +
+ )} + renderEmpty={() => ( + β€” no reading yet β€” + )} + /> + + + +
); } From a55d6e16c8a82c1d432027afc3cdc5dec6b31b05 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 18:06:58 +0530 Subject: [PATCH 47/66] remove outer padding and added readme.md --- README.md | 464 ++++++++++++++++++ .../GaugeChart/GaugeChartWidget.tsx | 8 +- src/styles/base.css | 17 +- src/themes/gaugeTheme.ts | 2 +- src/types/gauge.ts | 14 +- test/my-app/src/App.jsx | 66 ++- 6 files changed, 545 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 677c51ad..78c256ba 100644 --- a/README.md +++ b/README.md @@ -552,6 +552,470 @@ Neither state currently accepts style overrides via `styles` β€” flag it if you --- +### GaugeWidget + +An arc-style dial widget β€” shows a single value as a needle or filled arc between a `min` and `max`, with optional tick marks, a title, and a last-updated label. + +```jsx + +``` + +#### Required props + +| Prop | Type | Description | +| ---------- | -------- | --------------------------------- | +| `node` | `any` | `anedya.newNode(client, nodeId)` | +| `variable` | `string` | Variable name to display | + +> `node` is only required for **live-fetch mode**. `GaugeWidget` also supports a manual/static `value` mode that doesn't need a `node` at all β€” see [Manual value mode](#manual-value-mode--using-gauge-without-a-node) below. + +--- + +#### The styling model + +Like `CardWidget`, every visual piece of the gauge is a named **slot**, styled via CSS classes rather than inline styles: + +```ts +type GaugeSlot = + | "container" + | "title" + | "unit" + | "track" + | "bar" + | "needle" + | "needleCap" + | "value" + | "label" + | "tick" + | "tickLabel" + | "error" + | "empty"; +``` + +`track`, `bar`, `needle`, `needleCap`, `tick`, and `tickLabel` are all SVG elements β€” their color comes from the CSS `color` property via `currentColor` (e.g. `styles={{ bar: "text-indigo-500" }}`), rather than `fill`/`stroke`-specific Tailwind utilities. + +> **`track`, `bar`, `needle`, and `needleCap` have no default color class** β€” unlike `title`/`value`/`label`/`unit`, these four slots render invisible/black unless a theme (built-in or custom) sets a color, or you supply one directly via the `color`/`track.color`/`needle.needleColor` props (see [Arc, track, bar & needle](#arc-track-bar--needle) below). + +--- + +#### `styles` vs `className` + +Identical behavior to `CardWidget` β€” `styles` reaches any inner slot, `className` only touches the outermost container, and both compose together via `twMerge`: + +```jsx + +``` + +> Same rule as Card: `styles` classes must already exist in your app's compiled CSS β€” the widget doesn't generate CSS for them at build time. + +--- + +#### Theming + +`theme` accepts a built-in preset name or a full custom `WidgetTheme` object: + +```jsx +const emeraldTheme = { + styles: { + container: "", + title: "text-emerald-700", + unit: "text-emerald-600", + label: "text-emerald-400", + track: "text-emerald-100", + bar: "text-emerald-500", + needle: "text-emerald-800", + needleCap: "text-emerald-800", + value: "text-emerald-900", + tick: "text-emerald-200", + tickLabel: "text-emerald-500", + error: "text-red-600", + empty: "text-emerald-300", + }, +}; + + +// or + // built-in preset, or "light" (default) +``` + +Since `track`/`bar`/`needle`/`needleCap` have no built-in default color, a custom theme should set all of them explicitly β€” otherwise those elements fall back to unstyled `currentColor` inheritance from the page, not a sensible default. + +--- + +#### Tailwind responsive utilities + +Same mechanism as `CardWidget` β€” Tailwind's responsive prefixes work inside `styles` and are driven by the **browser viewport**, independent of the widget's own size: + +```jsx + +``` + +> **Exception β€” `tickLabel` font size:** the `tickLabel` slot's font size is always set via inline style from `tick.labelSize` (so it reliably scales with the tick geometry), which wins over any `text-*` class you put on `styles.tickLabel`. Use `tick.labelSize` to change tick label size; use `styles.tickLabel` for everything else (color, weight, tracking). + +--- + +#### `onDataChange` β€” data-driven rendering + +Same shape and precedence rules as `CardWidget`, with a gauge-specific data payload: + +```ts +{ + value: number; + timestamp: number; +} +``` + +```tsx + { + if (!data) return; + + const isCritical = data.value > 90; + return { + title: isCritical ? "Critical" : "Normal", + color: isCritical ? "#ef4444" : "#10b981", + needle: { needleColor: isCritical ? "#ef4444" : "#10b981" }, + styles: { + value: isCritical ? "text-red-500 animate-pulse" : "text-white", + }, + }; + }} +/> +``` + +Returning `undefined` (or nothing) clears any previous overrides and restores the widget's original props. `meta` behaves identically to Card's β€” see [Error & empty states](#error--empty-states). + +> **`onDataChange` only fires from live-fetch data.** In [manual value mode](#manual-value-mode--using-gauge-without-a-node) (no `node`), the fetch effect never runs, so `onDataChange` is always called with `data: null` exactly once and never again β€” it will not react to changes in your static `value` prop. + +--- + +#### How props are resolved + +Same layering as `CardWidget`: + +1. The props you pass to `` +2. Any temporary overrides returned from `onDataChange` +3. Theme resolution (`"light"`, `"dark"`, or a custom `WidgetTheme`) +4. Per-slot class resolution + +For each slot, classes are merged in this order: + +1. `GAUGE_DEFAULT_CLASSES` +2. Active theme classes +3. `styles` + +Later layers win on Tailwind conflicts, resolved via `twMerge`. `className` is separate from this chain and merges onto the outer container after `container` resolves. + +> **Rule of thumb:** defaults β†’ theme β†’ `styles` β†’ `onDataChange`. User overrides always win. + +--- + +#### Formatting vs rendering + +`format`, `formatOptions`, `decimalPlaces`, and `formatValue` follow the exact same precedence as `CardWidget`: `formatValue` β†’ `format` β†’ `decimalPlaces` β†’ raw value. + +```tsx + +// renders "512" + "MB" + + `${v.toFixed(1)}Β°`} /> +``` + +Preset table is identical to Card's β€” see [Formatters export](#formatters-export). `formatOptions` uses the same shape: + +```ts +{ + locale?: string; + binary?: boolean; // bytes only + toDecimalPlaces?: number; +} +``` + +> **Gauge clamps the value before formatting.** Unlike Card (which displays the raw fetched number as-is), Gauge always clamps the value to `[min, max]` first β€” `formatValue`/`format`/`decimalPlaces` all receive the **clamped** value, not the raw one. A reading of `120` on a `min={0} max={100}` gauge displays as `100`. + +##### Tick labels reuse the same `format` preset + +If `tick.show` is `true` and you haven't set `tick.labelFormat`, tick labels automatically use the same `format`/`formatOptions` as the main value β€” so the big number and the ring of tick labels stay unit-consistent without extra config: + +```tsx + +// tick labels: 0 B, 250 B, 500 B, 750 B, 1000 B β€” same scaling as the main value +``` + +Set `tick.labelFormat` to override just the ticks independently of the main value's formatting. + +--- + +#### The last-updated label + +Identical to `CardWidget` β€” `timezone`, `labelFormat`, `labelText` all work the same way, with the same preset table and precedence (`labelText` > `labelFormat` > default `"time"`). + +```tsx + +``` + +One gauge-specific addition: in [manual value mode](#manual-value-mode--using-gauge-without-a-node), there's no fetched timestamp to show a label for β€” Gauge falls back to the time the component **mounted**, captured once, so the label still renders something meaningful instead of disappearing entirely when you're driving the gauge with a static `value` prop. + +--- + +#### Manual value mode β€” using Gauge without a `node` + +Unlike `CardWidget`, `GaugeWidget` accepts a plain `value` prop and can render without ever fetching data: + +```tsx + +``` + +This is useful for gauges driven by something other than an Anedya node β€” a slider, computed value, form state, or a preview/demo context. + +When both `node` and `value` are supplied, live-fetched data always wins once it arrives β€” `value` only shows while no fetched value is available yet (e.g. before the first fetch resolves, or if `node` is omitted entirely). + +> `loading`, `error`, and empty states are exclusively products of the live-fetch path β€” they never trigger in manual value mode, since the fetch effect itself never runs without a `node`. + +--- + +#### Error & empty states + +Same three-outcome model as `CardWidget`, applicable only when using `node` (live-fetch mode): + +| State | When it happens | Default appearance | +|---|---|---| +| Success | Data was fetched normally | The arc/needle at the value, plus formatted value and label | +| Error | The fetch failed | The error message, styled via the `error` slot | +| Empty | The fetch succeeded, but no data exists yet | `"N/A"`, styled via the `empty` slot | + +```tsx + +``` + +##### `renderError` / `renderEmpty` + +```tsx + ( +
+ ⚠ Sensor unreachable + {error} +
+ )} + renderEmpty={() => β€” no reading yet β€”} +/> +``` + +Same rule as Card: when either is provided, it fully replaces the default `error`/`empty` element, so `styles.error`/`styles.empty` no longer apply. + +##### `onDataChange` meta + +```tsx + { + if (meta.kind === "error") return { renderError: () => Offline }; + if (meta.kind === "empty") return { renderEmpty: () => Waiting… }; + if (!data) return; + if (data.value > 90) return { title: "Critical", color: "#ef4444" }; + }} +/> +``` + +`meta.kind` is `"success" | "error" | "empty"`; `meta.error` is present only when `meta.kind === "error"`. + +--- + +#### Arc, track, bar & needle + +Gauge geometry is configured through four independent props. + +##### `arc` β€” the shape of the dial + +```ts +interface GaugeArcConfig { + startAngle?: number; // degrees, 0 = 12 o'clock, clockwise-positive. Default -90 + endAngle?: number; // Default 90 + radius?: number; // px β€” auto-fit to available space if omitted + thickness?: number; // px β€” auto-computed from radius if omitted + cornerRadius?: number; // rounds the ends of the bar/track. Default 0 +} +``` + +```tsx + // wider, near-full-circle dial + // full circle / donut + // rounded bar ends +``` + +##### `track` β€” the background ring + +```ts +interface GaugeTrackConfig { + show?: boolean; // default true + color?: string; // any CSS color β€” hex/rgb/hsl/named. Falls back to `currentColor` (styles.track) if unset +} +``` + +##### `color` β€” the filled bar + +Accepts a flat color or a gradient array β€” **this is a raw SVG fill value, not a Tailwind class**: + +```tsx + + + // linear gradient across the bar +``` + +For a Tailwind-class-driven bar color instead, use `styles={{ bar: "text-indigo-500" }}` β€” the two mechanisms are independent; `color` always wins over `styles.bar` when both are set, since `color` overrides the `currentColor` fallback entirely. + +##### `needle` + +```ts +interface GaugeNeedleConfig { + show?: boolean; // default true + type?: "line" | "rounded" | "drop" | "triangle"; // default "rounded" + length?: "short" | "medium" | "full" | number; // default "medium" + width?: number; // default 4 + color?: string; // shorthand for both needleColor and capColor + needleColor?: string; + capColor?: string; + capRadius?: number; // default 6 + animation?: boolean; // default true β€” see Animation below +} +``` + +```tsx + +``` + +##### No-needle ("donut") mode + +Setting `needle={{ show: false }}` switches the gauge into a donut-style display β€” the value/unit/label are centered directly over the arc instead of rendered below it: + +```tsx + +``` + +--- + +#### Tick marks + +```ts +interface GaugeTickConfig { + show?: boolean; // default false + count?: number; // number of INTERVALS, not marks. Default 10 β†’ 11 marks (0,10,...100) + size?: number; // tick line length in px. Default 6 + color?: string; // falls back to currentColor (styles.tick) + radiusOffset?: number; // gap between arc's outer edge and tick line start. Default 4 + labelGap?: number; // gap between tick line and its label. Default 4 + labelSize?: number; // tick label font size in px. Default 10 + labelColor?: string; // falls back to currentColor (styles.tickLabel) + labelFormat?: (value: number) => string; // overrides the auto-reused `format` preset (see above) +} +``` + +```tsx + +// marks at 0, 10, 20, 30, 40, 50 +``` + +The gauge automatically reserves extra space around the arc for the tick ring so ticks are never clipped by the SVG viewBox β€” this shrinks the drawn arc radius slightly whenever `tick.show` is `true`, which is expected. + +--- + +#### Animation + +```ts +interface GaugeAnimationConfig { + show?: boolean; // default true + duration?: number; // ms. Default 1000 + easing?: GaugeEasing; // default "cubicOut" +} +``` + +```tsx + + // arc/needle snap to value instantly, no tween +``` + +`easing` accepts any of d3-ease's standard names in short form: `linear`, `quadIn/Out/InOut`, `cubicIn/Out/InOut`, `sinIn/Out/InOut`, `expIn/Out/InOut`, `circleIn/Out/InOut`, `backIn/Out/InOut`, `elasticIn/Out/InOut`, `bounceIn/Out/InOut`. + +> The needle only animates when **both** `needle.animation` and `animation.show` are `true`. `animation.show: false` disables the bar's arc-fill animation as well as the needle's, regardless of `needle.animation`; `needle.animation: false` disables only the needle while the bar still tweens. + +--- + +#### Sizing + +```jsx + +``` + +Unlike `CardWidget`, the gauge has no auto-grow-to-content mode β€” it always fills whatever box it's given (its own container, or `width`/`height`/`size`), and the arc's radius is computed to fit that box. + +##### `size` + +A single number that fixes both width and height to a square-ish box and disables automatic size-tracking entirely β€” use this for a fixed, non-fluid gauge: + +```tsx + +``` + +##### Automatic sizing + +Without `size`, the gauge always tracks its parent container's actual rendered dimensions (via a `ResizeObserver`) and redraws the arc to fit β€” no separate flag needed to enable this, it's the default behavior whenever `size` is unset: + +```tsx + // fixed pixel height, fluid width + // fills a sized parent +``` + +If neither the parent nor `width`/`height`/`aspectRatio` constrain the box, the gauge falls back to a `240Γ—163`px default. + +--- + +#### Loading & error states + +While the initial fetch is in flight (live-fetch mode only), the gauge renders pulsing skeleton blocks in place of the value and label, sized to the current `--anedya-gauge-value-size` / `--anedya-gauge-label-size` CSS variables. The arc itself dims to reduced opacity rather than being replaced by a skeleton. + +Neither loading nor error states currently accept style overrides via `styles` beyond the `error`/`empty` slots described above. + +--- + +#### Other props + +| Prop | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------------------------ | +| `title` | `string` | Gauge title. Default: `"Latest Value"` | +| `value` | `number` | Manual/static value β€” see [Manual value mode](#manual-value-mode--using-gauge-without-a-node) | +| `min` | `number` | Minimum of the value range. Default `0` | +| `max` | `number` | Maximum of the value range. Default `100` | +| `unit` | `string` | Unit suffix shown next to the value (ignored while `format` is active) | +| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue`/`format` aren't provided) | + ## Stylesheet import This SDK ships pre-compiled CSS alongside its JavaScript β€” you don't need Tailwind configured in your own project for these widgets to render correctly, even if you don't use Tailwind at all. diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index 8ff8cd8d..f81c2fa8 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -52,7 +52,7 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { min?: number; max?: number; size?: number; - responsive?: boolean; + // responsive?: boolean; arc?: GaugeArcConfig; track?: GaugeTrackConfig; @@ -288,7 +288,7 @@ export function GaugeWidget({ min = 0, max = 100, size, - responsive = true, + // responsive = true, arc, track, color, @@ -406,7 +406,7 @@ export function GaugeWidget({ // ); const { ref: arcWrapperRef, size: dims } = useResizeObserver( - responsive && size == null + size == null ); const mergedStyles = useMemo( @@ -447,7 +447,7 @@ export function GaugeWidget({ renderEmpty, ...dynamicProps, styles: mergedStyles, - responsive, // not work + // responsive, // not work }; // ---- Resolved config ---- diff --git a/src/styles/base.css b/src/styles/base.css index ea653721..70c78609 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -31,21 +31,20 @@ container-type: size; container-name: anedya-gauge; transition: width 0.25s ease, height 0.25s ease; -} +} .anedya-gauge { - --anedya-gauge-padding: clamp(0.75rem, 0.4rem + 2cqw + 2cqh, 1.5rem); - --anedya-gauge-gap: clamp(0.25rem, 0.1rem + 1cqw + 1cqh, 0.75rem); - - --anedya-gauge-title-size: clamp(0.875rem, 0.6rem + 1.2cqw + 1.2cqh, 1.25rem); - --anedya-gauge-value-size: clamp(1.75rem, 1rem + 4cqw + 4cqh, 3.5rem); - --anedya-gauge-unit-size: clamp(0.875rem, 0.6rem + 1cqw + 1cqh, 1.25rem); - --anedya-gauge-label-size: clamp(0.75rem, 0.5rem + 0.8cqw + 0.8cqh, 1rem); + --anedya-gauge-padding: clamp(1rem, 0.5rem + 2.5cqw + 2.5cqh, 4.5rem); + --anedya-gauge-title-size: clamp(0.875rem, 0.6rem + 1.5cqw + 1.5cqh, 3rem); + --anedya-gauge-value-size: clamp(2.25rem, 1rem + 8cqw + 8cqh, 9.5rem); + --anedya-gauge-unit-size: clamp(1rem, 0.7rem + 1.5cqw + 1.5cqh, 3.25rem); + --anedya-gauge-label-size: clamp(0.75rem, 0.5rem + 1.2cqw + 1.2cqh, 2.25rem); --anedya-gauge-tick-size: clamp(0.625rem, 0.4rem + 0.6cqw + 0.6cqh, 0.875rem); + --anedya-gauge-gap: 0.25rem; /* flat 4px */ transition: padding 0.25s ease, gap 0.25s ease; } -.anedya-gauge > * { +.anedya-gauge>* { transition: font-size 0.25s ease; } \ No newline at end of file diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index 486ac3bc..fec54702 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -5,7 +5,7 @@ import { WidgetTheme } from "../types/root"; export const GAUGE_DEFAULT_CLASSES: Record = { container: - "flex flex-col items-center justify-center text-center gap-[var(--anedya-gauge-gap)] p-[var(--anedya-gauge-padding)]", + "flex flex-col items-center justify-center text-center", title: "text-[length:var(--anedya-gauge-title-size)] font-medium", unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", track: "", diff --git a/src/types/gauge.ts b/src/types/gauge.ts index 018d1373..8c939f67 100644 --- a/src/types/gauge.ts +++ b/src/types/gauge.ts @@ -75,13 +75,13 @@ export interface GaugeNeedleConfig { animation?: boolean; } -export interface GaugeValueLabelConfig { - show?: boolean; - precision?: number; - prefix?: string; - suffix?: string; - formatter?: (value: number) => string; -} +// export interface GaugeValueLabelConfig { +// show?: boolean; +// precision?: number; +// prefix?: string; +// suffix?: string; +// formatter?: (value: number) => string; +// } /** REQUIREMENT 3/4: radial min/max tick marks drawn around the arc. */ export interface GaugeTickConfig { diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 8e498efa..a21ddf67 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -378,13 +378,14 @@ export default function App() { { if (!data) { return { title: "No Data", color: "#6b7280", - styles: { value: "text-slate-500" }, }; } @@ -404,7 +405,9 @@ export default function App() { // per-slot class overrides β€” merges with (doesn't replace) the static `styles` prop styles: { - value: isCritical ? "text-red-500 animate-pulse" : "text-black", + value: isCritical + ? "text-red-500 animate-pulse" + : "text-yellow-500", title: isCritical ? "text-red-400" : "text-slate-400", }, }; @@ -413,9 +416,11 @@ export default function App() { ( @@ -431,17 +436,68 @@ export default function App() { + + -
); } From dbbf69c49b300b6f1dbd5f244acf5e06e5ccde43 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 18:11:06 +0530 Subject: [PATCH 48/66] added table of content --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 78c256ba..45d88684 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat ## Table of Contents -- [Installation & Setup](#installation--setup) - [Widgets](#widgets) - [CardWidget](#cardwidget) - [Required props](#required-props) @@ -23,14 +22,18 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) - [How props are resolved](#how-props-are-resolved) - [Formatting vs rendering](#formatting-vs-rendering) + - [GaugeWidget](#gaugewidget) + - [Required props](#required-props-1) + - [The styling model](#the-styling-model-1) + - [Theming](#theming-1) + - [Manual value mode](#manual-value-mode--using-gauge-without-a-node) + - [Arc, track, bar & needle](#arc-track-bar--needle) + - [Tick marks](#tick-marks) + - [Animation](#animation) + - [Sizing](#sizing-1) - [The last-updated label](#the-last-updated-label) - [Error & empty states](#error--empty-states) - [Formatters export](#formatters-export) - - [Sizing](#sizing) - - [Responsive sizing](#responsive-sizing) - - [Loading & error states](#loading--error-states) - - [Other props](#other-props) -- [Stylesheet import](#stylesheet-import) --- From 76a70abce6749b8646075bb53f64456c857c22dd Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 18:24:48 +0530 Subject: [PATCH 49/66] update readme.md --- README.md | 524 +++++++++++++++------------------------- test/my-app/src/App.jsx | 1 + 2 files changed, 201 insertions(+), 324 deletions(-) diff --git a/README.md b/README.md index 45d88684..3a40eba7 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat ## Table of Contents +- [Installation & Setup](#installation--setup) - [Widgets](#widgets) - [CardWidget](#cardwidget) - [Required props](#required-props) @@ -22,18 +23,31 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) - [How props are resolved](#how-props-are-resolved) - [Formatting vs rendering](#formatting-vs-rendering) - - [GaugeWidget](#gaugewidget) - - [Required props](#required-props-1) - - [The styling model](#the-styling-model-1) - - [Theming](#theming-1) - - [Manual value mode](#manual-value-mode--using-gauge-without-a-node) - - [Arc, track, bar & needle](#arc-track-bar--needle) - - [Tick marks](#tick-marks) - - [Animation](#animation) - - [Sizing](#sizing-1) - [The last-updated label](#the-last-updated-label) - [Error & empty states](#error--empty-states) - [Formatters export](#formatters-export) + - [Sizing](#sizing) + - [Responsive sizing](#responsive-sizing) + - [Loading & error states](#loading--error-states) + - [Other props](#other-props) +- [GaugeWidget](#gaugewidget) + - [Required props](#required-props-1) + - [Manual vs live values](#manual-vs-live-values) + - [Slots & styling](#slots--styling) + - [Arc configuration](#arc-configuration) + - [Track configuration](#track-configuration) + - [Bar color & gradients](#bar-color--gradients) + - [Needle configuration](#needle-configuration) + - [Needle-less (donut) mode](#needle-less-donut-mode) + - [Tick marks](#tick-marks) + - [Animation configuration](#animation-configuration) + - [Formatting the value](#formatting-the-value) + - [The last-updated label](#the-last-updated-label-1) + - [Error & empty states](#error--empty-states-1) + - [Sizing](#sizing-1) + - [Responsive sizing](#responsive-sizing-1) + - [Other props](#other-props-1) +- [Stylesheet import](#stylesheet-import) --- @@ -557,16 +571,16 @@ Neither state currently accepts style overrides via `styles` β€” flag it if you ### GaugeWidget -An arc-style dial widget β€” shows a single value as a needle or filled arc between a `min` and `max`, with optional tick marks, a title, and a last-updated label. +A radial arc gauge β€” shows a single value as a filled arc with an optional needle, min/max tick marks, and a last-updated label. ```jsx ``` @@ -577,447 +591,309 @@ An arc-style dial widget β€” shows a single value as a needle or filled arc betw | `node` | `any` | `anedya.newNode(client, nodeId)` | | `variable` | `string` | Variable name to display | -> `node` is only required for **live-fetch mode**. `GaugeWidget` also supports a manual/static `value` mode that doesn't need a `node` at all β€” see [Manual value mode](#manual-value-mode--using-gauge-without-a-node) below. - --- -#### The styling model +#### Manual vs live values -Like `CardWidget`, every visual piece of the gauge is a named **slot**, styled via CSS classes rather than inline styles: +Unlike `CardWidget`, `GaugeWidget` can also render **without** a live `node` fetch β€” pass `value` directly for a fully controlled gauge (e.g. driven by your own state, a slider, or a value computed elsewhere in your app): -```ts -type GaugeSlot = - | "container" - | "title" - | "unit" - | "track" - | "bar" - | "needle" - | "needleCap" - | "value" - | "label" - | "tick" - | "tickLabel" - | "error" - | "empty"; +```jsx + ``` -`track`, `bar`, `needle`, `needleCap`, `tick`, and `tickLabel` are all SVG elements β€” their color comes from the CSS `color` property via `currentColor` (e.g. `styles={{ bar: "text-indigo-500" }}`), rather than `fill`/`stroke`-specific Tailwind utilities. +If both a `node`/`variable` fetch *and* a `value` prop are present, the fetched value takes over once it arrives β€” `value` acts as the initial/fallback reading until then. -> **`track`, `bar`, `needle`, and `needleCap` have no default color class** β€” unlike `title`/`value`/`label`/`unit`, these four slots render invisible/black unless a theme (built-in or custom) sets a color, or you supply one directly via the `color`/`track.color`/`needle.needleColor` props (see [Arc, track, bar & needle](#arc-track-bar--needle) below). +`min` and `max` (default `0` / `100`) define the gauge's range regardless of which mode you're in. The displayed value is always clamped into `[min, max]` before it's drawn or formatted. --- -#### `styles` vs `className` +#### Slots & styling -Identical behavior to `CardWidget` β€” `styles` reaches any inner slot, `className` only touches the outermost container, and both compose together via `twMerge`: +Like `CardWidget`, every part of the gauge is a named **slot**, and the same `styles` (per-slot) / `className` (outer container only) / `theme` system applies: + +```ts +type GaugeSlot = + | "container" | "title" | "unit" | "track" | "bar" + | "needle" | "needleCap" | "value" | "label" + | "tick" | "tickLabel" | "error" | "empty"; +``` ```jsx ``` -> Same rule as Card: `styles` classes must already exist in your app's compiled CSS β€” the widget doesn't generate CSS for them at build time. - ---- - -#### Theming - -`theme` accepts a built-in preset name or a full custom `WidgetTheme` object: +`theme` works exactly as it does for `CardWidget` β€” a preset name or a custom `WidgetTheme` object: ```jsx -const emeraldTheme = { +const emeraldGaugeTheme = { styles: { - container: "", - title: "text-emerald-700", - unit: "text-emerald-600", - label: "text-emerald-400", - track: "text-emerald-100", bar: "text-emerald-500", - needle: "text-emerald-800", - needleCap: "text-emerald-800", + track: "text-emerald-100", value: "text-emerald-900", - tick: "text-emerald-200", - tickLabel: "text-emerald-500", - error: "text-red-600", - empty: "text-emerald-300", + needle: "text-emerald-700", + needleCap: "text-emerald-700", }, }; - + // or // built-in preset, or "light" (default) ``` -Since `track`/`bar`/`needle`/`needleCap` have no built-in default color, a custom theme should set all of them explicitly β€” otherwise those elements fall back to unstyled `currentColor` inheritance from the page, not a sensible default. +Slot resolution order is the same defaults β†’ theme β†’ `styles` β†’ `onDataChange` chain described under CardWidget, and `onDataChange` on `GaugeWidget` can likewise return a partial set of props (including `styles`) to temporarily override the widget based on the incoming reading β€” see [`onDataChange`](#ondatachange--data-driven-rendering) above; the gauge version has the same signature, just with `GaugeData`/`GaugeDataMeta` in place of the card's types. + +> **Note:** `track`, `bar`, `needle`, and `needleCap` are SVG shapes, not text β€” their "color" comes from `currentColor`, which is why these slots are styled with Tailwind text-color utilities (`text-emerald-500`) rather than `fill-*`/`stroke-*` classes. --- -#### Tailwind responsive utilities +#### Arc configuration -Same mechanism as `CardWidget` β€” Tailwind's responsive prefixes work inside `styles` and are driven by the **browser viewport**, independent of the widget's own size: +`arc` controls the shape of the gauge itself: ```jsx ``` -> **Exception β€” `tickLabel` font size:** the `tickLabel` slot's font size is always set via inline style from `tick.labelSize` (so it reliably scales with the tick geometry), which wins over any `text-*` class you put on `styles.tickLabel`. Use `tick.labelSize` to change tick label size; use `styles.tickLabel` for everything else (color, weight, tracking). - ---- - -#### `onDataChange` β€” data-driven rendering - -Same shape and precedence rules as `CardWidget`, with a gauge-specific data payload: - -```ts -{ - value: number; - timestamp: number; -} -``` - -```tsx - { - if (!data) return; - - const isCritical = data.value > 90; - return { - title: isCritical ? "Critical" : "Normal", - color: isCritical ? "#ef4444" : "#10b981", - needle: { needleColor: isCritical ? "#ef4444" : "#10b981" }, - styles: { - value: isCritical ? "text-red-500 animate-pulse" : "text-white", - }, - }; - }} -/> -``` +| Prop | Type | Default | Description | +| -------------- | -------- | --------------------------- | -------------------------------------------------------------------- | +| `startAngle` | `number` | `-90` | Degrees, `0` = 12 o'clock, clockwise-positive | +| `endAngle` | `number` | `90` | Degrees, same convention as `startAngle` | +| `radius` | `number` | auto-fit to container | Capped to whatever actually fits the current width/height/tick space | +| `thickness` | `number` | `~18%` of resolved radius | Arc/bar stroke width in px | +| `cornerRadius` | `number` | `0` | Rounds the ends of both the track and the value bar | -Returning `undefined` (or nothing) clears any previous overrides and restores the widget's original props. `meta` behaves identically to Card's β€” see [Error & empty states](#error--empty-states). +A default `startAngle`/`endAngle` of `-90`/`90` draws the classic bottom half-circle speedometer; narrowing the range (e.g. `-120`/`120`) draws a fuller arc. -> **`onDataChange` only fires from live-fetch data.** In [manual value mode](#manual-value-mode--using-gauge-without-a-node) (no `node`), the fetch effect never runs, so `onDataChange` is always called with `data: null` exactly once and never again β€” it will not react to changes in your static `value` prop. +`radius` is a *maximum* β€” the gauge always shrinks it further if needed so the arc (plus tick marks, if shown) fits inside the widget's actual rendered box. --- -#### How props are resolved - -Same layering as `CardWidget`: +#### Track configuration -1. The props you pass to `` -2. Any temporary overrides returned from `onDataChange` -3. Theme resolution (`"light"`, `"dark"`, or a custom `WidgetTheme`) -4. Per-slot class resolution +`track` is the background arc the value bar sits on top of: -For each slot, classes are merged in this order: - -1. `GAUGE_DEFAULT_CLASSES` -2. Active theme classes -3. `styles` - -Later layers win on Tailwind conflicts, resolved via `twMerge`. `className` is separate from this chain and merges onto the outer container after `container` resolves. +```jsx + +``` -> **Rule of thumb:** defaults β†’ theme β†’ `styles` β†’ `onDataChange`. User overrides always win. +| Prop | Type | Default | Description | +| ------- | --------- | ---------------------- | ----------------------------------------------- | +| `show` | `boolean` | `true` | Whether the background track arc is drawn | +| `color` | `string` | theme's `track` slot | Overrides the track color directly (any CSS color) | --- -#### Formatting vs rendering - -`format`, `formatOptions`, `decimalPlaces`, and `formatValue` follow the exact same precedence as `CardWidget`: `formatValue` β†’ `format` β†’ `decimalPlaces` β†’ raw value. +#### Bar color & gradients -```tsx - -// renders "512" + "MB" +`color` sets the fill of the value arc β€” a single color, or 2+ colors for a gradient: - `${v.toFixed(1)}Β°`} /> -``` - -Preset table is identical to Card's β€” see [Formatters export](#formatters-export). `formatOptions` uses the same shape: +```jsx + -```ts -{ - locale?: string; - binary?: boolean; // bytes only - toDecimalPlaces?: number; -} + +// renders a left-to-right gradient across the filled portion of the arc ``` -> **Gauge clamps the value before formatting.** Unlike Card (which displays the raw fetched number as-is), Gauge always clamps the value to `[min, max]` first β€” `formatValue`/`format`/`decimalPlaces` all receive the **clamped** value, not the raw one. A reading of `120` on a `min={0} max={100}` gauge displays as `100`. +If omitted, the bar falls back to the theme's `bar` slot color via `currentColor`. -##### Tick labels reuse the same `format` preset +--- -If `tick.show` is `true` and you haven't set `tick.labelFormat`, tick labels automatically use the same `format`/`formatOptions` as the main value β€” so the big number and the ring of tick labels stay unit-consistent without extra config: +#### Needle configuration -```tsx +```jsx -// tick labels: 0 B, 250 B, 500 B, 750 B, 1000 B β€” same scaling as the main value ``` -Set `tick.labelFormat` to override just the ticks independently of the main value's formatting. +| Prop | Type | Default | Description | +| ------------- | ------------------------------------------------ | -------------- | ----------------------------------------------------------------------------- | +| `show` | `boolean` | `true` | Whether the needle is drawn at all | +| `type` | `"line" \| "rounded" \| "drop" \| "triangle"` | `"rounded"` | Needle shape | +| `length` | `"short" \| "medium" \| "full" \| number` | `"medium"` | Preset (relative to the resolved radius) or an explicit px value | +| `width` | `number` | `4` | Needle thickness in px | +| `color` | `string` | β€” | Shorthand β€” sets both `needleColor` and `capColor` at once | +| `needleColor` | `string` | `color` or theme | Color of the needle shape specifically, overrides `color` for the shape only | +| `capColor` | `string` | `color` or theme | Color of the center cap circle specifically | +| `capRadius` | `number` | `6` | Radius of the center cap circle in px | +| `animation` | `boolean` | `true` | Whether the needle rotates smoothly to its new position | ---- - -#### The last-updated label - -Identical to `CardWidget` β€” `timezone`, `labelFormat`, `labelText` all work the same way, with the same preset table and precedence (`labelText` > `labelFormat` > default `"time"`). - -```tsx - -``` - -One gauge-specific addition: in [manual value mode](#manual-value-mode--using-gauge-without-a-node), there's no fetched timestamp to show a label for β€” Gauge falls back to the time the component **mounted**, captured once, so the label still renders something meaningful instead of disappearing entirely when you're driving the gauge with a static `value` prop. +`needle.animation` and the top-level `animation.show` (below) are independent switches β€” **both** must be `true` for the needle to animate. This lets you, for example, animate the bar fill while snapping the needle instantly, or vice versa. --- -#### Manual value mode β€” using Gauge without a `node` +#### Needle-less (donut) mode -Unlike `CardWidget`, `GaugeWidget` accepts a plain `value` prop and can render without ever fetching data: +Setting `needle={{ show: false }}` turns the gauge into a donut-style indicator β€” the value/unit/label block is centered directly over the arc instead of rendered below it: -```tsx - +```jsx + ``` -This is useful for gauges driven by something other than an Anedya node β€” a slider, computed value, form state, or a preview/demo context. - -When both `node` and `value` are supplied, live-fetched data always wins once it arrives β€” `value` only shows while no fetched value is available yet (e.g. before the first fetch resolves, or if `node` is omitted entirely). - -> `loading`, `error`, and empty states are exclusively products of the live-fetch path β€” they never trigger in manual value mode, since the fetch effect itself never runs without a `node`. - --- -#### Error & empty states - -Same three-outcome model as `CardWidget`, applicable only when using `node` (live-fetch mode): - -| State | When it happens | Default appearance | -|---|---|---| -| Success | Data was fetched normally | The arc/needle at the value, plus formatted value and label | -| Error | The fetch failed | The error message, styled via the `error` slot | -| Empty | The fetch succeeded, but no data exists yet | `"N/A"`, styled via the `empty` slot | - -```tsx - -``` - -##### `renderError` / `renderEmpty` - -```tsx - ( -
- ⚠ Sensor unreachable - {error} -
- )} - renderEmpty={() => β€” no reading yet β€”} -/> -``` - -Same rule as Card: when either is provided, it fully replaces the default `error`/`empty` element, so `styles.error`/`styles.empty` no longer apply. +#### Tick marks -##### `onDataChange` meta +`tick` draws radial marks (and optional labels) around the arc between `min` and `max`. Off by default: -```tsx +```jsx { - if (meta.kind === "error") return { renderError: () => Offline }; - if (meta.kind === "empty") return { renderEmpty: () => Waiting… }; - if (!data) return; - if (data.value > 90) return { title: "Critical", color: "#ef4444" }; + tick={{ + show: true, + count: 10, // number of INTERVALS, so 10 -> 11 marks (0,10,...,100) + size: 6, + radiusOffset: 4, // gap between the arc's outer edge and the tick line + labelGap: 4, // gap between the tick line and its label + labelSize: 10, // px β€” always wins over any styles.tickLabel font-size class + color: "#cbd5e1", + labelColor: "#94a3b8", + labelFormat: (v) => `${v}Β°`, }} /> ``` -`meta.kind` is `"success" | "error" | "empty"`; `meta.error` is present only when `meta.kind === "error"`. - ---- +| Prop | Type | Default | Description | +| -------------- | -------------------------- | ------- | ----------------------------------------------------------------------------------------------- | +| `show` | `boolean` | `false` | Whether tick marks are drawn | +| `count` | `number` | `10` | Number of **intervals** between `min` and `max` β€” `count: 10` draws 11 marks | +| `size` | `number` | `6` | Tick line length in px | +| `color` | `string` | β€” | Tick line color; falls back to the theme's `tick` slot via `currentColor` | +| `radiusOffset` | `number` | `4` | Gap in px between the arc's outer edge and the start of the tick line | +| `labelGap` | `number` | `4` | Gap in px between the end of the tick line and its label | +| `labelSize` | `number` | `10` | Tick label font size in px β€” set as an inline style, so it always wins over `styles.tickLabel` | +| `labelColor` | `string` | β€” | Tick label color; falls back to the theme's `tickLabel` slot | +| `labelFormat` | `(value: number) => string`| β€” | Custom formatter for tick numbers. If omitted, reuses the widget's `format` preset if one is set, otherwise a plain rounded number | -#### Arc, track, bar & needle +Enabling ticks reserves extra space inside the widget for the line + gaps + label, shrinking the arc's radius slightly so the ring is never clipped β€” you don't need to size the container any differently to accommodate it. -Gauge geometry is configured through four independent props. +> Because `labelSize` is applied as an inline style, a `styles.tickLabel` class controlling font size will have no effect β€” use the `labelSize` prop for sizing, and `styles.tickLabel` / `tickLabel` theme classes for anything else (weight, tracking, etc.). -##### `arc` β€” the shape of the dial - -```ts -interface GaugeArcConfig { - startAngle?: number; // degrees, 0 = 12 o'clock, clockwise-positive. Default -90 - endAngle?: number; // Default 90 - radius?: number; // px β€” auto-fit to available space if omitted - thickness?: number; // px β€” auto-computed from radius if omitted - cornerRadius?: number; // rounds the ends of the bar/track. Default 0 -} -``` +--- -```tsx - // wider, near-full-circle dial - // full circle / donut - // rounded bar ends -``` +#### Animation configuration -##### `track` β€” the background ring +`animation` controls the transition when the value (and, if enabled, the needle) moves to a new reading: -```ts -interface GaugeTrackConfig { - show?: boolean; // default true - color?: string; // any CSS color β€” hex/rgb/hsl/named. Falls back to `currentColor` (styles.track) if unset -} +```jsx + ``` -##### `color` β€” the filled bar +| Prop | Type | Default | Description | +| ---------- | ------------- | ------------ | -------------------------------------------------------- | +| `show` | `boolean` | `true` | Whether the bar (and needle, if also enabled) animates | +| `duration` | `number` | `1000` | Transition duration in ms | +| `easing` | `GaugeEasing` | `"cubicOut"` | Any of the standard d3-ease families β€” `linear`, `quadIn/Out/InOut`, `cubicIn/Out/InOut`, `sinIn/Out/InOut`, `expIn/Out/InOut`, `circleIn/Out/InOut`, `backIn/Out/InOut`, `elasticIn/Out/InOut`, `bounceIn/Out/InOut` | -Accepts a flat color or a gradient array β€” **this is a raw SVG fill value, not a Tailwind class**: +With `animation.show: false`, both the bar and needle snap directly to the new value with no transition, regardless of `needle.animation`. -```tsx - - - // linear gradient across the bar -``` - -For a Tailwind-class-driven bar color instead, use `styles={{ bar: "text-indigo-500" }}` β€” the two mechanisms are independent; `color` always wins over `styles.bar` when both are set, since `color` overrides the `currentColor` fallback entirely. +--- -##### `needle` +#### Formatting the value -```ts -interface GaugeNeedleConfig { - show?: boolean; // default true - type?: "line" | "rounded" | "drop" | "triangle"; // default "rounded" - length?: "short" | "medium" | "full" | number; // default "medium" - width?: number; // default 4 - color?: string; // shorthand for both needleColor and capColor - needleColor?: string; - capColor?: string; - capRadius?: number; // default 6 - animation?: boolean; // default true β€” see Animation below -} -``` +`GaugeWidget` uses the exact same formatting system as `CardWidget` β€” `format` (named presets), `formatOptions`, `decimalPlaces`, and `formatValue` all behave identically and share the same precedence (`formatValue` > `format` > `decimalPlaces` > raw value). See [Formatting vs rendering](#formatting-vs-rendering) above for the full preset table and examples; everything there applies unchanged here, e.g.: -```tsx - +```jsx + + + `${v.toFixed(1)}%`} /> ``` -##### No-needle ("donut") mode - -Setting `needle={{ show: false }}` switches the gauge into a donut-style display β€” the value/unit/label are centered directly over the arc instead of rendered below it: - -```tsx - -``` +As with Card, `format` takes over the `unit` slot entirely while active, and presets don't validate that they semantically match your data β€” only use one that fits what the value actually represents. --- -#### Tick marks +#### The last-updated label -```ts -interface GaugeTickConfig { - show?: boolean; // default false - count?: number; // number of INTERVALS, not marks. Default 10 β†’ 11 marks (0,10,...100) - size?: number; // tick line length in px. Default 6 - color?: string; // falls back to currentColor (styles.tick) - radiusOffset?: number; // gap between arc's outer edge and tick line start. Default 4 - labelGap?: number; // gap between tick line and its label. Default 4 - labelSize?: number; // tick label font size in px. Default 10 - labelColor?: string; // falls back to currentColor (styles.tickLabel) - labelFormat?: (value: number) => string; // overrides the auto-reused `format` preset (see above) -} -``` +Also identical to `CardWidget` β€” `labelFormat` presets (`time`, `date`, `datetime`, `relative`, `iso`), the `labelText` escape hatch, and `timezone` override all work the same way. See [The last-updated label](#the-last-updated-label) above. -```tsx - -// marks at 0, 10, 20, 30, 40, 50 +```jsx + + ``` -The gauge automatically reserves extra space around the arc for the tick ring so ticks are never clipped by the SVG viewBox β€” this shrinks the drawn arc radius slightly whenever `tick.show` is `true`, which is expected. +One gauge-specific note: in **manual mode** (a `value` prop with no `node`), there's no fetched timestamp to show. In that case the label falls back to the moment the widget first mounted, so the label still renders something meaningful instead of disappearing. --- -#### Animation +#### Error & empty states -```ts -interface GaugeAnimationConfig { - show?: boolean; // default true - duration?: number; // ms. Default 1000 - easing?: GaugeEasing; // default "cubicOut" -} -``` +Same three outcomes as `CardWidget` β€” success, error (fetch failed), and empty (fetch succeeded, no data yet) β€” styled via the `error`/`empty` slots, with `renderError(error)` / `renderEmpty()` available for full custom rendering. See [Error & empty states](#error--empty-states) above; behavior and precedence are unchanged for `GaugeWidget`. -```tsx - - // arc/needle snap to value instantly, no tween +```jsx + ⚠ {error}} + renderEmpty={() => β€” no reading yet β€”} +/> ``` -`easing` accepts any of d3-ease's standard names in short form: `linear`, `quadIn/Out/InOut`, `cubicIn/Out/InOut`, `sinIn/Out/InOut`, `expIn/Out/InOut`, `circleIn/Out/InOut`, `backIn/Out/InOut`, `elasticIn/Out/InOut`, `bounceIn/Out/InOut`. - -> The needle only animates when **both** `needle.animation` and `animation.show` are `true`. `animation.show: false` disables the bar's arc-fill animation as well as the needle's, regardless of `needle.animation`; `needle.animation: false` disables only the needle while the bar still tweens. +`onDataChange` also receives the same `(data, meta)` shape as Card, where `meta.kind` is `"success" | "error" | "empty"`. --- #### Sizing ```jsx - + + // shorthand: sets width AND height to the same value (a square gauge) ``` -Unlike `CardWidget`, the gauge has no auto-grow-to-content mode β€” it always fills whatever box it's given (its own container, or `width`/`height`/`size`), and the arc's radius is computed to fit that box. - -##### `size` - -A single number that fixes both width and height to a square-ish box and disables automatic size-tracking entirely β€” use this for a fixed, non-fluid gauge: +`size` takes priority over `width`/`height` when set. Without `size` or `height`, the gauge fills its container's width and derives a proportional height automatically (unless `aspectRatio` is set). -```tsx - -``` - -##### Automatic sizing - -Without `size`, the gauge always tracks its parent container's actual rendered dimensions (via a `ResizeObserver`) and redraws the arc to fit β€” no separate flag needed to enable this, it's the default behavior whenever `size` is unset: - -```tsx - // fixed pixel height, fluid width - // fills a sized parent -``` - -If neither the parent nor `width`/`height`/`aspectRatio` constrain the box, the gauge falls back to a `240Γ—163`px default. +| Prop | Type | Description | +| ------------- | -------- | -------------------------------------------------------------------------- | +| `size` | `number` | Shorthand for equal `width`/`height` β€” a fixed square gauge | +| `width` | `number` | Container width in px | +| `height` | `number` | Container height in px | +| `minWidth` | `number` | Minimum container width in px | +| `maxWidth` | `number` | Maximum container width in px | +| `minHeight` | `number` | Minimum container height in px | +| `maxHeight` | `number` | Maximum container height in px | +| `aspectRatio` | `number` | Width-to-height ratio used when neither `size` nor `height` is set | --- -#### Loading & error states +#### Responsive sizing -While the initial fetch is in flight (live-fetch mode only), the gauge renders pulsing skeleton blocks in place of the value and label, sized to the current `--anedya-gauge-value-size` / `--anedya-gauge-label-size` CSS variables. The arc itself dims to reduced opacity rather than being replaced by a skeleton. +Like `CardWidget`, the gauge uses CSS Container Queries to scale internal typography and spacing (title/value/unit/label font sizes, gaps) based on its own rendered box, not the browser viewport β€” no configuration needed, and it composes the same way with Tailwind responsive prefixes in `styles` as described under [Responsive sizing](#responsive-sizing) above. -Neither loading nor error states currently accept style overrides via `styles` beyond the `error`/`empty` slots described above. +The arc's radius itself is handled separately (it's a geometry calculation, not a CSS variable) β€” it auto-fits to whatever space is left after padding and, if enabled, tick-mark space is subtracted, capped by `arc.radius` when you set one explicitly. --- #### Other props -| Prop | Type | Description | -| --------------- | -------- | ------------------------------------------------------------------------------------ | -| `title` | `string` | Gauge title. Default: `"Latest Value"` | -| `value` | `number` | Manual/static value β€” see [Manual value mode](#manual-value-mode--using-gauge-without-a-node) | -| `min` | `number` | Minimum of the value range. Default `0` | -| `max` | `number` | Maximum of the value range. Default `100` | -| `unit` | `string` | Unit suffix shown next to the value (ignored while `format` is active) | -| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue`/`format` aren't provided) | +| Prop | Type | Description | +| --------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------- | +| `title` | `string` | Gauge title. Default: `"Latest Value"` | +| `value` | `number` | Manual/controlled value. Used as the initial value, or the only value if no `node` is given | +| `min` | `number` | Minimum of the gauge's range. Default: `0` | +| `max` | `number` | Maximum of the gauge's range. Default: `100` | +| `unit` | `string` | Unit suffix shown next to the value | +| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | + ## Stylesheet import diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index a21ddf67..f2f602b0 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -498,6 +498,7 @@ export default function App() { }} size={400} /> +
); } From f142a07c0a310b04c789ef54ced8e923eb0d3ef6 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 18:43:06 +0530 Subject: [PATCH 50/66] commit --- README.md | 860 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 473 insertions(+), 387 deletions(-) diff --git a/README.md b/README.md index 3a40eba7..5a33a99f 100644 --- a/README.md +++ b/README.md @@ -22,31 +22,29 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [Tailwind responsive utilities](#tailwind-responsive-utilities) - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) - [How props are resolved](#how-props-are-resolved) + - [GaugeWidget](#gaugewidget) + - [Required props](#required-props-1) + - [Manual vs live values](#manual-vs-live-values) + - [Slots & styling](#slots--styling) + - [Theming](#theming-1) + - [Arc configuration](#arc-configuration) + - [Track configuration](#track-configuration) + - [Bar color & gradients](#bar-color--gradients) + - [Needle configuration](#needle-configuration) + - [Needle-less (donut) mode](#needle-less-donut-mode) + - [Tick marks](#tick-marks) + - [Animation configuration](#animation-configuration) + - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering-1) + - [How props are resolved](#how-props-are-resolved-1) +- [Common](#common) - [Formatting vs rendering](#formatting-vs-rendering) -- [The last-updated label](#the-last-updated-label) -- [Error & empty states](#error--empty-states) -- [Formatters export](#formatters-export) + - [The last-updated label](#the-last-updated-label) + - [Error & empty states](#error--empty-states) + - [Formatters export](#formatters-export) - [Sizing](#sizing) - [Responsive sizing](#responsive-sizing) - [Loading & error states](#loading--error-states) - [Other props](#other-props) -- [GaugeWidget](#gaugewidget) - - [Required props](#required-props-1) - - [Manual vs live values](#manual-vs-live-values) - - [Slots & styling](#slots--styling) - - [Arc configuration](#arc-configuration) - - [Track configuration](#track-configuration) - - [Bar color & gradients](#bar-color--gradients) - - [Needle configuration](#needle-configuration) - - [Needle-less (donut) mode](#needle-less-donut-mode) - - [Tick marks](#tick-marks) - - [Animation configuration](#animation-configuration) - - [Formatting the value](#formatting-the-value) - - [The last-updated label](#the-last-updated-label-1) - - [Error & empty states](#error--empty-states-1) - - [Sizing](#sizing-1) - - [Responsive sizing](#responsive-sizing-1) - - [Other props](#other-props-1) - [Stylesheet import](#stylesheet-import) --- @@ -105,7 +103,7 @@ A single-value display widget β€” shows the latest reading, a title, and a last- #### Required props | Prop | Type | Description | -| ---------- | -------- | -------------------------------- | +| ---------- | -------- | --------------------------------- | | `node` | `any` | `anedya.newNode(client, nodeId)` | | `variable` | `string` | Variable name to display | @@ -128,9 +126,9 @@ type CardSlot = "container" | "title" | "value" | "unit" | "label"; These look similar but do genuinely different things: | | Shape | Targets | Purpose | -| ----------- | --------------------- | -------------------------------------------------------------------- | ------------------------------------------------------ | -| `styles` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) _and_ `container` | reach inside the widget | -| `className` | plain string | only the outermost container element | the ordinary React convention every component supports | +| ----------- | ---------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------- | +| `styles` | object, keyed by slot | any inner slot (`title`, `value`, `unit`, `label`) _and_ `container` | reach inside the widget | +| `className` | plain string | only the outermost container element | the ordinary React convention every component supports | ```jsx +``` + +#### Required props + +| Prop | Type | Description | +| ---------- | -------- | --------------------------------- | +| `node` | `any` | `anedya.newNode(client, nodeId)` | +| `variable` | `string` | Variable name to display | + +--- + +#### Manual vs live values + +Unlike `CardWidget`, `GaugeWidget` can also render **without** a live `node` fetch β€” pass `value` directly for a fully controlled gauge (e.g. driven by your own state, a slider, or a value computed elsewhere in your app): + +```jsx + +``` + +If both a `node`/`variable` fetch *and* a `value` prop are present, the fetched value takes over once it arrives β€” `value` acts as the initial/fallback reading until then. + +`min` and `max` (default `0` / `100`) define the gauge's range regardless of which mode you're in. The displayed value is always clamped into `[min, max]` before it's drawn or formatted. + +--- + +#### Slots & styling + +Like `CardWidget`, every part of the gauge is a named **slot**, and the same `styles` (per-slot) / `className` (outer container only) system applies: + +```ts +type GaugeSlot = + | "container" | "title" | "unit" | "track" | "bar" + | "needle" | "needleCap" | "value" | "label" + | "tick" | "tickLabel" | "error" | "empty"; +``` + +```jsx + +``` + +> **Note:** `track`, `bar`, `needle`, and `needleCap` are SVG shapes, not text β€” their "color" comes from `currentColor`, which is why these slots are styled with Tailwind text-color utilities (`text-emerald-500`) rather than `fill-*`/`stroke-*` classes. + +--- + +#### Theming + +`theme` works exactly as it does for `CardWidget` β€” a preset name, or a custom `WidgetTheme` object: + +```jsx +const emeraldGaugeTheme = { + styles: { + bar: "text-emerald-500", + track: "text-emerald-100", + value: "text-emerald-900", + needle: "text-emerald-700", + needleCap: "text-emerald-700", + }, +}; + + +// or + // built-in preset, or "light" (default) +``` + +--- + +#### Arc configuration + +`arc` controls the shape of the gauge itself: + +```jsx + +``` + +| Prop | Type | Default | Description | +| -------------- | -------- | ---------------------------- | ------------------------------------------------------------------------ | +| `startAngle` | `number` | `-90` | Degrees, `0` = 12 o'clock, clockwise-positive | +| `endAngle` | `number` | `90` | Degrees, same convention as `startAngle` | +| `radius` | `number` | auto-fit to container | Capped to whatever actually fits the current width/height/tick space | +| `thickness` | `number` | `~18%` of resolved radius | Arc/bar stroke width in px | +| `cornerRadius` | `number` | `0` | Rounds the ends of both the track and the value bar | + +A default `startAngle`/`endAngle` of `-90`/`90` draws the classic bottom half-circle speedometer; narrowing the range (e.g. `-120`/`120`) draws a fuller arc. + +`radius` is a *maximum* β€” the gauge always shrinks it further if needed so the arc (plus tick marks, if shown) fits inside the widget's actual rendered box. + +--- + +#### Track configuration + +`track` is the background arc the value bar sits on top of: + +```jsx + +``` + +| Prop | Type | Default | Description | +| ------- | --------- | ---------------------- | ------------------------------------------------------- | +| `show` | `boolean` | `true` | Whether the background track arc is drawn | +| `color` | `string` | theme's `track` slot | Overrides the track color directly (any CSS color) | + +--- + +#### Bar color & gradients + +`color` sets the fill of the value arc β€” a single color, or 2+ colors for a gradient: + +```jsx + + + +// renders a left-to-right gradient across the filled portion of the arc +``` + +If omitted, the bar falls back to the theme's `bar` slot color via `currentColor`. + +--- + +#### Needle configuration + +```jsx + +``` + +| Prop | Type | Default | Description | +| ------------- | ------------------------------------------------ | ----------------- | ----------------------------------------------------------------------------------- | +| `show` | `boolean` | `true` | Whether the needle is drawn at all | +| `type` | `"line" \| "rounded" \| "drop" \| "triangle"` | `"rounded"` | Needle shape | +| `length` | `"short" \| "medium" \| "full" \| number` | `"medium"` | Preset (relative to the resolved radius) or an explicit px value | +| `width` | `number` | `4` | Needle thickness in px | +| `color` | `string` | β€” | Shorthand β€” sets both `needleColor` and `capColor` at once | +| `needleColor` | `string` | `color` or theme | Color of the needle shape specifically, overrides `color` for the shape only | +| `capColor` | `string` | `color` or theme | Color of the center cap circle specifically | +| `capRadius` | `number` | `6` | Radius of the center cap circle in px | +| `animation` | `boolean` | `true` | Whether the needle rotates smoothly to its new position | + +`needle.animation` and the top-level `animation.show` (below) are independent switches β€” **both** must be `true` for the needle to animate. This lets you, for example, animate the bar fill while snapping the needle instantly, or vice versa. + +--- + +#### Needle-less (donut) mode + +Setting `needle={{ show: false }}` turns the gauge into a donut-style indicator β€” the value/unit/label block is centered directly over the arc instead of rendered below it: + +```jsx + +``` + +--- + +#### Tick marks + +`tick` draws radial marks (and optional labels) around the arc between `min` and `max`. Off by default: + +```jsx + 11 marks (0,10,...,100) + size: 6, + radiusOffset: 4, // gap between the arc's outer edge and the tick line + labelGap: 4, // gap between the tick line and its label + labelSize: 10, // px β€” always wins over any styles.tickLabel font-size class + color: "#cbd5e1", + labelColor: "#94a3b8", + labelFormat: (v) => `${v}Β°`, + }} +/> +``` + +| Prop | Type | Default | Description | +| -------------- | ---------------------------- | ------- | --------------------------------------------------------------------------------------------------- | +| `show` | `boolean` | `false` | Whether tick marks are drawn | +| `count` | `number` | `10` | Number of **intervals** between `min` and `max` β€” `count: 10` draws 11 marks | +| `size` | `number` | `6` | Tick line length in px | +| `color` | `string` | β€” | Tick line color; falls back to the theme's `tick` slot via `currentColor` | +| `radiusOffset` | `number` | `4` | Gap in px between the arc's outer edge and the start of the tick line | +| `labelGap` | `number` | `4` | Gap in px between the end of the tick line and its label | +| `labelSize` | `number` | `10` | Tick label font size in px β€” set as an inline style, so it always wins over `styles.tickLabel` | +| `labelColor` | `string` | β€” | Tick label color; falls back to the theme's `tickLabel` slot | +| `labelFormat` | `(value: number) => string` | β€” | Custom formatter for tick numbers. If omitted, reuses the widget's `format` preset if one is set, otherwise a plain rounded number | + +Enabling ticks reserves extra space inside the widget for the line + gaps + label, shrinking the arc's radius slightly so the ring is never clipped β€” you don't need to size the container any differently to accommodate it. + +> Because `labelSize` is applied as an inline style, a `styles.tickLabel` class controlling font size will have no effect β€” use the `labelSize` prop for sizing, and `styles.tickLabel` / `tickLabel` theme classes for anything else (weight, tracking, etc.). + +--- + +#### Animation configuration + +`animation` controls the transition when the value (and, if enabled, the needle) moves to a new reading: + +```jsx + +``` + +| Prop | Type | Default | Description | +| ---------- | ------------- | ------------ | -------------------------------------------------------------- | +| `show` | `boolean` | `true` | Whether the bar (and needle, if also enabled) animates | +| `duration` | `number` | `1000` | Transition duration in ms | +| `easing` | `GaugeEasing` | `"cubicOut"` | Any of the standard d3-ease families β€” `linear`, `quadIn/Out/InOut`, `cubicIn/Out/InOut`, `sinIn/Out/InOut`, `expIn/Out/InOut`, `circleIn/Out/InOut`, `backIn/Out/InOut`, `elasticIn/Out/InOut`, `bounceIn/Out/InOut` | + +With `animation.show: false`, both the bar and needle snap directly to the new value with no transition, regardless of `needle.animation`. + +--- + +#### `onDataChange` β€” data-driven rendering + +`onDataChange` works the same way it does on `CardWidget` (see [`onDataChange` under CardWidget](#ondatachange--data-driven-rendering)) β€” it's called with the latest fetched reading and a `meta` object, and can return a partial set of props (including `styles`) that temporarily override the gauge's own props: + +```tsx + { + if (meta.kind === "error") { + return { renderError: () => Offline }; + } + if (!data) return; + if (data.value > 80) { + return { color: "#ef4444", theme: "dark" }; + } + }} +/> +``` + +The only difference from Card is the data shape passed in β€” `GaugeData` (`{ value, timestamp }`) and `GaugeDataMeta` β€” but the resolution behavior (temporary override until the callback runs again; `undefined`/nothing clears it) is identical. + +--- + +#### How props are resolved + +Rendering follows the same layered order as `CardWidget`: + +1. The props you pass to `` +2. Any temporary overrides returned from `onDataChange` +3. Theme resolution (`"light"`, `"dark"`, or a custom `WidgetTheme`) +4. Per-slot class resolution + +For each slot (`container`, `title`, `unit`, `track`, `bar`, `needle`, `needleCap`, `value`, `label`, `tick`, `tickLabel`, `error`, `empty`), classes are merged in this order: + +1. `GAUGE_DEFAULT_CLASSES` +2. Active theme classes +3. `styles` + +Later layers win whenever two Tailwind utilities conflict, resolved with `twMerge`. `className` is separate from this chain β€” merged onto the outer container after the container slot has been resolved. + +> **Rule of thumb:** defaults β†’ theme β†’ `styles` β†’ `onDataChange`. User overrides always win. + +--- + +## Common + +The sections below apply to every widget in this SDK. Where behavior is identical, only the shared explanation is given once; each subsection includes an example for both `CardWidget` and `GaugeWidget`. + +### Formatting vs rendering `format`, `formatOptions`, `decimalPlaces`, and `labelFormat` control **what text is displayed**. @@ -257,11 +548,12 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve `onDataChange` can override any of these (along with most other widget props), allowing the widget to react to incoming data. -##### `format` β€” named presets for common unit types +#### `format` β€” named presets for common unit types For values that need unit-aware scaling (bytes, durations, lengths, etc.), pass a `format` preset instead of manually computing a unit string: ```tsx +// CardWidget // renders "512" + "MB" β€” auto-scaled, no manual unit needed @@ -272,6 +564,15 @@ For values that need unit-aware scaling (bytes, durations, lengths, etc.), pass // renders "1.25" + "km" ``` +```tsx +// GaugeWidget + +// renders "512" + "MB" on the value, and (if tick.show is on) scaled units on tick labels too + + +// renders "2d 4h 12m" +``` + Available presets: | Preset | Input | Output example | @@ -282,7 +583,7 @@ Available presets: | `length` | meters | `"1.25"` + `"km"` β€” auto-scales mm/cm/m/km | | `volume` | milliliters | auto-scales mL/L | | `dataRate` | bits per second | auto-scales bps/Kbps/Mbps | -| `percent` | 0–100 | `"45%"` | +| `percent` | 0–100 | `"45%"` | `formatOptions` accepts: @@ -301,7 +602,7 @@ Available presets: // "1,23,456" (Indian digit grouping) instead of "123,456" - + // "123.456" (German uses "." as the thousands separator, "," as the decimal point) ``` @@ -310,7 +611,7 @@ Available presets: // "512.34" + "MB" β€” more decimal places than the default - + // "512" + "MB" β€” whole number, no decimals ``` @@ -323,42 +624,56 @@ Available presets: // raw 1048576 -> "1.05" + "MB" β€” matches how storage manufacturers/network specs are usually reported ``` As a rule of thumb: use `binary: true` for memory/RAM/file-size-on-disk readings, and the default (decimal) for network throughput or storage capacity marketing figures. - -**`format` takes over the `unit` slot entirely.** When set, the preset determines its own unit per value (e.g. switching from `"KB"` to `"MB"` as a byte count grows) β€” the `unit` prop is ignored while `format` is active. + +**`format` takes over the `unit` slot entirely.** When set, the preset determines its own unit per value (e.g. switching from `"KB"` to `"MB"` as a byte count grows) β€” the `unit` prop is ignored while `format` is active. On `GaugeWidget`, if `tick.labelFormat` isn't set, enabled tick labels also reuse the active `format` preset, so the value and the tick ring stay unit-consistent. > **Presets don't validate that they match your data's actual meaning** β€” they only know how to scale a raw number. Applying `format="length"` to a Celsius reading, for example, will scale it as if it were meters and display a plausible-looking but semantically wrong unit. Only use a preset that matches what the underlying value actually represents. -##### Precedence +#### Precedence `formatValue` always wins if provided β€” it's a full custom formatting function and bypasses `format`/`decimalPlaces` entirely: ```tsx +// CardWidget `${v.toFixed(2)} % RH`} labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} /> ``` -> Long `formatValue` output (e.g. `"56.00 % RH"`) may wrap onto a second line at small widths β€” the value slot wraps rather than overflowing. See [Sizing](#sizing) for how this interacts with a fixed `height`. +```tsx +// GaugeWidget + `${v.toFixed(1)}%`} + labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} +/> +``` + +> Long `formatValue` output (e.g. `"56.00 % RH"`) may wrap onto a second line at small widths β€” the value slot wraps rather than overflowing. On `CardWidget` this interacts with a fixed `height` β€” see [Sizing](#sizing) below. On `GaugeWidget`, the value block sits below (or centered over, in needle-less mode) the arc and wraps the same way within the available space. --- -#### The last-updated label +### The last-updated label By default, the label under the value shows a fixed clock time (`"Updated 14:32:10"`). This can be changed with `labelFormat`, or fully replaced with `labelText`. -##### `timezone` β€” override auto-detection +#### `timezone` β€” override auto-detection ```tsx // shows the timestamp converted to Eastern time, regardless of the visitor's own browser timezone + + +// shows the timestamp converted to Indian Standard Time ``` If omitted, the widget uses `Intl.DateTimeFormat().resolvedOptions().timeZone` β€” the browser's own detected timezone. Pass any IANA timezone name (e.g. `"Asia/Kolkata"`, `"Europe/London"`) to force a specific one instead β€” useful for dashboards where all viewers should see times in the device's local timezone rather than their own. `timezone` affects the `time`, `date`, and `datetime` label presets. It has no effect on `relative` (a time difference is timezone-independent) or `iso` (ISO 8601 output is always UTC by definition). -##### `labelFormat` β€” named presets +> **`GaugeWidget` in manual mode:** if you're using `value` without a `node` (see [Manual vs live values](#manual-vs-live-values)), there's no fetched timestamp to show. The label falls back to the moment the widget first mounted, so it still renders something meaningful instead of disappearing. + +#### `labelFormat` β€” named presets ```tsx @@ -366,19 +681,22 @@ If omitted, the widget uses `Intl.DateTimeFormat().resolvedOptions().timeZone` // "Updated 7/24/2026" + + +// "5 minutes ago" instead of "Updated 14:32:10" ``` Available presets: | Preset | Output example | -| ---------------- | --------------------------------- | -| `time` (default) | `"Updated 14:32:10"` | -| `date` | `"Updated 7/24/2026"` | -| `datetime` | `"Updated 7/24/2026, 2:32:10 PM"` | -| `relative` | `"5 minutes ago"` | -| `iso` | `"2026-07-24T14:32:10.000Z"` | +| ---------------- | ---------------------------------- | +| `time` (default) | `"Updated 14:32:10"` | +| `date` | `"Updated 7/24/2026"` | +| `datetime` | `"Updated 7/24/2026, 2:32:10 PM"` | +| `relative` | `"5 minutes ago"` | +| `iso` | `"2026-07-24T14:32:10.000Z"` | -##### `labelText` β€” full custom control +#### `labelText` β€” full custom control `labelText` always takes precedence over `labelFormat` and receives the raw timestamp, so you can use it for anything the presets don't cover β€” 12-hour/AM-PM formatting, hours-only, non-default locales, or combining relative time with custom surrounding text: @@ -397,16 +715,18 @@ import { relativeTime } from "public-widget-sdk/formatters"; `Last synced ${relativeTime(ts)}`} />; // "Last synced 5 minutes ago" + + `Last synced ${relativeTime(ts)}`} />; +// "Last synced 5 minutes ago" ``` `labelFormat` covers the common cases with zero code; `labelText` is the general escape hatch for everything else β€” the same relationship `formatValue` has with `format`. --- +### Error & empty states -#### Error & empty states - -The card distinguishes between three outcomes of a fetch, each rendered differently: +Every widget distinguishes between three outcomes of a fetch, each rendered differently: | State | When it happens | Default appearance | |---|---|---| @@ -424,9 +744,17 @@ Both `error` and `empty` are real slots, so they pick up theme colors automatica empty: "text-slate-300", }} /> + + ``` -##### `renderError` / `renderEmpty` β€” full custom rendering +#### `renderError` / `renderEmpty` β€” full custom rendering For full control beyond just restyling text, `renderError` and `renderEmpty` let you replace the entire error/empty state with your own JSX: @@ -441,13 +769,24 @@ For full control beyond just restyling text, `renderError` and `renderEmpty` let )} renderEmpty={() => β€” no reading yet β€”} /> + + ( +
+ ⚠ Sensor unreachable + {error} +
+ )} + renderEmpty={() => β€” no reading yet β€”} +/> ``` `renderError` receives the raw error message string; `renderEmpty` takes no arguments. When either is provided, it fully replaces the default `error`/`empty` slot rendering β€” the corresponding `styles.error`/`styles.empty` classes are ignored in that case, since there's no default element left for them to apply to. -##### Reacting to errors/empty state via `onDataChange` +#### Reacting to errors/empty state via `onDataChange` -`onDataChange` now receives a second argument describing which state just occurred, so you can react to errors or empty data the same way you already react to values: +`onDataChange` receives a second argument describing which state just occurred, so you can react to errors or empty data the same way you already react to values: ```tsx + + { + if (meta.kind === "error") { + return { renderError: () => Offline }; + } + if (meta.kind === "empty") { + return { renderEmpty: () => Waiting for first reading… }; + } + if (!data) return; + if (data.value > 80) { + return { color: "#ef4444", theme: "dark" }; + } + }} +/> ``` `meta.kind` is one of `"success"`, `"error"`, or `"empty"`; `meta.error` is present only when `meta.kind === "error"`, carrying the underlying error message. @@ -473,19 +828,23 @@ This is backwards compatible β€” existing `onDataChange={(data) => {...}}` callb --- -#### Formatters export +### Formatters export -The formatting helpers used internally are also available as a standalone import, for composing into your own `labelText`/`formatValue` functions: +The formatting helpers used internally are also available as a standalone import, for composing into your own `labelText`/`formatValue` functions β€” usable with either widget: ```tsx import { relativeTime } from "public-widget-sdk/formatters"; ``` | Export | Signature | Description | -| -------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | +| -------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | | `relativeTime` | `(timestamp: number, locale?: string) => string` | Converts a timestamp into a human-relative string (`"5 minutes ago"`). Accepts seconds or milliseconds. | -#### Sizing +--- + +### Sizing + +#### CardWidget `width` / `height` / `minWidth` / `maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole `styles`/theme system: @@ -498,7 +857,7 @@ import { relativeTime } from "public-widget-sdk/formatters"; Whether you pass `height` changes how the card behaves β€” this is intentional, not a quirk: | | Behavior | -| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`height` omitted** | The card **auto-grows** to fit its content. If `formatValue`/`labelText` produce long text that wraps, the card simply becomes taller. Sizing scales with **width only**. | | **`height` passed** | The card becomes a **fixed-size box**. Sizing scales with **both width and height** (see [Responsive sizing](#responsive-sizing)). If content is too tall to fit (e.g. a long wrapped value at a small height), it is **clipped**, not overflowed β€” the card will not grow past the height you gave it. | @@ -512,11 +871,33 @@ Whether you pass `height` changes how the card behaves β€” this is intentional, If you're using a `formatValue` that can produce long strings, either don't pass a fixed `height` (let the card grow to fit), or pass a `height` generous enough for the wrapped text at your chosen `width`. +#### GaugeWidget + +```jsx + + // shorthand: sets width AND height to the same value (a square gauge) +``` + +`size` takes priority over `width`/`height` when both are set. Without `size` or `height`, the gauge fills its container's width and derives a proportional height automatically (unless `aspectRatio` is set). + +| Prop | Type | Description | +| ------------- | -------- | -------------------------------------------------------------------------- | +| `size` | `number` | Shorthand for equal `width`/`height` β€” a fixed square gauge | +| `width` | `number` | Container width in px | +| `height` | `number` | Container height in px | +| `minWidth` | `number` | Minimum container width in px | +| `maxWidth` | `number` | Maximum container width in px | +| `minHeight` | `number` | Minimum container height in px | +| `maxHeight` | `number` | Maximum container height in px | +| `aspectRatio` | `number` | Width-to-height ratio used when neither `size` nor `height` is set | + +Unlike Card, the gauge doesn't clip content past a fixed `height` β€” instead, the arc's radius and internal spacing shrink to fit whatever box is available (see [Responsive sizing](#responsive-sizing) below). + --- -#### Responsive sizing +### Responsive sizing -The widget automatically scales its internal spacing and typography using **CSS Container Queries** β€” based on the card's own rendered size, not the browser viewport. +The widget automatically scales its internal spacing and typography using **CSS Container Queries** β€” based on the widget's own rendered size, not the browser viewport. By default the following properties scale automatically: @@ -527,374 +908,79 @@ By default the following properties scale automatically: - label font size - spacing (`gap`) -**When `height` is omitted**, scaling responds to the card's **width only** (`cqw`). +**When `height` is omitted**, scaling responds to the container's **width only** (`cqw`). -**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size card renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. +**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size container renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. -A card inside a narrow dashboard column will use smaller typography than the same card rendered full-width, even on the same screen β€” this behavior is built in and needs no configuration. +A widget inside a narrow dashboard column will use smaller typography than the same widget rendered full-width, even on the same screen β€” this behavior is built in and needs no configuration. -##### Overriding responsive sizing +#### Overriding responsive sizing If you provide your own font-size utility for a slot, you're opting out of the default responsive sizing for that slot. ```tsx +// CardWidget -``` - -The value will always render at `text-6xl`. Likewise, responsive Tailwind classes (`text-2xl md:text-5xl`) take precedence over the widget's default responsive sizing β€” your classes always win over the widget defaults. - ---- - -#### Loading & error states - -While the initial fetch is in flight, the card renders **skeleton loaders** in place of the value and label β€” pulsing placeholder blocks sized to match each slot's current font-size variable (`var(--anedya-card-value-size)` / `var(--anedya-card-label-size)`), so the skeleton scales along with the card exactly like the real content would. - -If the fetch fails or no data is available, the card renders the error message text in place of the value (title still renders normally). - -Neither state currently accepts style overrides via `styles` β€” flag it if you need to customize their appearance. - ---- - -#### Other props - -| Prop | Type | Description | -| --------------- | -------- | ---------------------------------------------------------------------------------- | -| `title` | `string` | Card title. Default: `"Latest Value"` | -| `unit` | `string` | Unit suffix shown next to the value | -| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | - ---- - -### GaugeWidget - -A radial arc gauge β€” shows a single value as a filled arc with an optional needle, min/max tick marks, and a last-updated label. - -```jsx - -``` - -#### Required props - -| Prop | Type | Description | -| ---------- | -------- | --------------------------------- | -| `node` | `any` | `anedya.newNode(client, nodeId)` | -| `variable` | `string` | Variable name to display | - ---- - -#### Manual vs live values - -Unlike `CardWidget`, `GaugeWidget` can also render **without** a live `node` fetch β€” pass `value` directly for a fully controlled gauge (e.g. driven by your own state, a slider, or a value computed elsewhere in your app): - -```jsx - -``` - -If both a `node`/`variable` fetch *and* a `value` prop are present, the fetched value takes over once it arrives β€” `value` acts as the initial/fallback reading until then. - -`min` and `max` (default `0` / `100`) define the gauge's range regardless of which mode you're in. The displayed value is always clamped into `[min, max]` before it's drawn or formatted. - ---- - -#### Slots & styling - -Like `CardWidget`, every part of the gauge is a named **slot**, and the same `styles` (per-slot) / `className` (outer container only) / `theme` system applies: - -```ts -type GaugeSlot = - | "container" | "title" | "unit" | "track" | "bar" - | "needle" | "needleCap" | "value" | "label" - | "tick" | "tickLabel" | "error" | "empty"; -``` -```jsx +// GaugeWidget -``` - -`theme` works exactly as it does for `CardWidget` β€” a preset name or a custom `WidgetTheme` object: - -```jsx -const emeraldGaugeTheme = { - styles: { - bar: "text-emerald-500", - track: "text-emerald-100", - value: "text-emerald-900", - needle: "text-emerald-700", - needleCap: "text-emerald-700", - }, -}; - - -// or - // built-in preset, or "light" (default) -``` - -Slot resolution order is the same defaults β†’ theme β†’ `styles` β†’ `onDataChange` chain described under CardWidget, and `onDataChange` on `GaugeWidget` can likewise return a partial set of props (including `styles`) to temporarily override the widget based on the incoming reading β€” see [`onDataChange`](#ondatachange--data-driven-rendering) above; the gauge version has the same signature, just with `GaugeData`/`GaugeDataMeta` in place of the card's types. - -> **Note:** `track`, `bar`, `needle`, and `needleCap` are SVG shapes, not text β€” their "color" comes from `currentColor`, which is why these slots are styled with Tailwind text-color utilities (`text-emerald-500`) rather than `fill-*`/`stroke-*` classes. - ---- - -#### Arc configuration - -`arc` controls the shape of the gauge itself: - -```jsx - -``` - -| Prop | Type | Default | Description | -| -------------- | -------- | --------------------------- | -------------------------------------------------------------------- | -| `startAngle` | `number` | `-90` | Degrees, `0` = 12 o'clock, clockwise-positive | -| `endAngle` | `number` | `90` | Degrees, same convention as `startAngle` | -| `radius` | `number` | auto-fit to container | Capped to whatever actually fits the current width/height/tick space | -| `thickness` | `number` | `~18%` of resolved radius | Arc/bar stroke width in px | -| `cornerRadius` | `number` | `0` | Rounds the ends of both the track and the value bar | - -A default `startAngle`/`endAngle` of `-90`/`90` draws the classic bottom half-circle speedometer; narrowing the range (e.g. `-120`/`120`) draws a fuller arc. - -`radius` is a *maximum* β€” the gauge always shrinks it further if needed so the arc (plus tick marks, if shown) fits inside the widget's actual rendered box. - ---- - -#### Track configuration - -`track` is the background arc the value bar sits on top of: - -```jsx - -``` - -| Prop | Type | Default | Description | -| ------- | --------- | ---------------------- | ----------------------------------------------- | -| `show` | `boolean` | `true` | Whether the background track arc is drawn | -| `color` | `string` | theme's `track` slot | Overrides the track color directly (any CSS color) | - ---- - -#### Bar color & gradients - -`color` sets the fill of the value arc β€” a single color, or 2+ colors for a gradient: - -```jsx - - - -// renders a left-to-right gradient across the filled portion of the arc -``` - -If omitted, the bar falls back to the theme's `bar` slot color via `currentColor`. - ---- - -#### Needle configuration - -```jsx - -``` - -| Prop | Type | Default | Description | -| ------------- | ------------------------------------------------ | -------------- | ----------------------------------------------------------------------------- | -| `show` | `boolean` | `true` | Whether the needle is drawn at all | -| `type` | `"line" \| "rounded" \| "drop" \| "triangle"` | `"rounded"` | Needle shape | -| `length` | `"short" \| "medium" \| "full" \| number` | `"medium"` | Preset (relative to the resolved radius) or an explicit px value | -| `width` | `number` | `4` | Needle thickness in px | -| `color` | `string` | β€” | Shorthand β€” sets both `needleColor` and `capColor` at once | -| `needleColor` | `string` | `color` or theme | Color of the needle shape specifically, overrides `color` for the shape only | -| `capColor` | `string` | `color` or theme | Color of the center cap circle specifically | -| `capRadius` | `number` | `6` | Radius of the center cap circle in px | -| `animation` | `boolean` | `true` | Whether the needle rotates smoothly to its new position | - -`needle.animation` and the top-level `animation.show` (below) are independent switches β€” **both** must be `true` for the needle to animate. This lets you, for example, animate the bar fill while snapping the needle instantly, or vice versa. - ---- - -#### Needle-less (donut) mode - -Setting `needle={{ show: false }}` turns the gauge into a donut-style indicator β€” the value/unit/label block is centered directly over the arc instead of rendered below it: - -```jsx - -``` - ---- - -#### Tick marks - -`tick` draws radial marks (and optional labels) around the arc between `min` and `max`. Off by default: - -```jsx - 11 marks (0,10,...,100) - size: 6, - radiusOffset: 4, // gap between the arc's outer edge and the tick line - labelGap: 4, // gap between the tick line and its label - labelSize: 10, // px β€” always wins over any styles.tickLabel font-size class - color: "#cbd5e1", - labelColor: "#94a3b8", - labelFormat: (v) => `${v}Β°`, + value: "text-6xl", }} /> ``` -| Prop | Type | Default | Description | -| -------------- | -------------------------- | ------- | ----------------------------------------------------------------------------------------------- | -| `show` | `boolean` | `false` | Whether tick marks are drawn | -| `count` | `number` | `10` | Number of **intervals** between `min` and `max` β€” `count: 10` draws 11 marks | -| `size` | `number` | `6` | Tick line length in px | -| `color` | `string` | β€” | Tick line color; falls back to the theme's `tick` slot via `currentColor` | -| `radiusOffset` | `number` | `4` | Gap in px between the arc's outer edge and the start of the tick line | -| `labelGap` | `number` | `4` | Gap in px between the end of the tick line and its label | -| `labelSize` | `number` | `10` | Tick label font size in px β€” set as an inline style, so it always wins over `styles.tickLabel` | -| `labelColor` | `string` | β€” | Tick label color; falls back to the theme's `tickLabel` slot | -| `labelFormat` | `(value: number) => string`| β€” | Custom formatter for tick numbers. If omitted, reuses the widget's `format` preset if one is set, otherwise a plain rounded number | - -Enabling ticks reserves extra space inside the widget for the line + gaps + label, shrinking the arc's radius slightly so the ring is never clipped β€” you don't need to size the container any differently to accommodate it. - -> Because `labelSize` is applied as an inline style, a `styles.tickLabel` class controlling font size will have no effect β€” use the `labelSize` prop for sizing, and `styles.tickLabel` / `tickLabel` theme classes for anything else (weight, tracking, etc.). - ---- - -#### Animation configuration - -`animation` controls the transition when the value (and, if enabled, the needle) moves to a new reading: - -```jsx - -``` - -| Prop | Type | Default | Description | -| ---------- | ------------- | ------------ | -------------------------------------------------------- | -| `show` | `boolean` | `true` | Whether the bar (and needle, if also enabled) animates | -| `duration` | `number` | `1000` | Transition duration in ms | -| `easing` | `GaugeEasing` | `"cubicOut"` | Any of the standard d3-ease families β€” `linear`, `quadIn/Out/InOut`, `cubicIn/Out/InOut`, `sinIn/Out/InOut`, `expIn/Out/InOut`, `circleIn/Out/InOut`, `backIn/Out/InOut`, `elasticIn/Out/InOut`, `bounceIn/Out/InOut` | - -With `animation.show: false`, both the bar and needle snap directly to the new value with no transition, regardless of `needle.animation`. - ---- - -#### Formatting the value - -`GaugeWidget` uses the exact same formatting system as `CardWidget` β€” `format` (named presets), `formatOptions`, `decimalPlaces`, and `formatValue` all behave identically and share the same precedence (`formatValue` > `format` > `decimalPlaces` > raw value). See [Formatting vs rendering](#formatting-vs-rendering) above for the full preset table and examples; everything there applies unchanged here, e.g.: - -```jsx - - - `${v.toFixed(1)}%`} /> -``` - -As with Card, `format` takes over the `unit` slot entirely while active, and presets don't validate that they semantically match your data β€” only use one that fits what the value actually represents. - ---- - -#### The last-updated label - -Also identical to `CardWidget` β€” `labelFormat` presets (`time`, `date`, `datetime`, `relative`, `iso`), the `labelText` escape hatch, and `timezone` override all work the same way. See [The last-updated label](#the-last-updated-label) above. - -```jsx - - -``` +The value will always render at `text-6xl`. Likewise, responsive Tailwind classes (`text-2xl md:text-5xl`) take precedence over the widget's default responsive sizing β€” your classes always win over the widget defaults. -One gauge-specific note: in **manual mode** (a `value` prop with no `node`), there's no fetched timestamp to show. In that case the label falls back to the moment the widget first mounted, so the label still renders something meaningful instead of disappearing. +> **GaugeWidget note:** the arc's radius itself is handled separately from these CSS variables (it's a geometry calculation, not a font size) β€” it auto-fits to whatever space is left after padding and, if enabled, tick-mark space is subtracted, capped by `arc.radius` when you set one explicitly. --- -#### Error & empty states - -Same three outcomes as `CardWidget` β€” success, error (fetch failed), and empty (fetch succeeded, no data yet) β€” styled via the `error`/`empty` slots, with `renderError(error)` / `renderEmpty()` available for full custom rendering. See [Error & empty states](#error--empty-states) above; behavior and precedence are unchanged for `GaugeWidget`. +### Loading & error states -```jsx - ⚠ {error}} - renderEmpty={() => β€” no reading yet β€”} -/> -``` +#### CardWidget -`onDataChange` also receives the same `(data, meta)` shape as Card, where `meta.kind` is `"success" | "error" | "empty"`. +While the initial fetch is in flight, the card renders **skeleton loaders** in place of the value and label β€” pulsing placeholder blocks sized to match each slot's current font-size variable (`var(--anedya-card-value-size)` / `var(--anedya-card-label-size)`), so the skeleton scales along with the card exactly like the real content would. ---- +If the fetch fails or no data is available, the card renders the error message text in place of the value (title still renders normally). -#### Sizing +Neither state currently accepts style overrides via `styles` β€” flag it if you need to customize their appearance. -```jsx - - // shorthand: sets width AND height to the same value (a square gauge) -``` +#### GaugeWidget -`size` takes priority over `width`/`height` when set. Without `size` or `height`, the gauge fills its container's width and derives a proportional height automatically (unless `aspectRatio` is set). +While the initial fetch is in flight, the gauge renders the same kind of pulsing skeleton blocks in place of the value and label (sized against `var(--anedya-gauge-value-size)` / `var(--anedya-gauge-label-size)`), and the arc/needle themselves render at reduced opacity rather than disappearing, so the gauge's shape stays visible while data loads. -| Prop | Type | Description | -| ------------- | -------- | -------------------------------------------------------------------------- | -| `size` | `number` | Shorthand for equal `width`/`height` β€” a fixed square gauge | -| `width` | `number` | Container width in px | -| `height` | `number` | Container height in px | -| `minWidth` | `number` | Minimum container width in px | -| `maxWidth` | `number` | Maximum container width in px | -| `minHeight` | `number` | Minimum container height in px | -| `maxHeight` | `number` | Maximum container height in px | -| `aspectRatio` | `number` | Width-to-height ratio used when neither `size` nor `height` is set | +If the fetch fails or no data is available, the error message (or `renderError`/`renderEmpty` output) replaces the value/label block; the arc still renders behind it at the gauge's minimum value. --- -#### Responsive sizing +### Other props -Like `CardWidget`, the gauge uses CSS Container Queries to scale internal typography and spacing (title/value/unit/label font sizes, gaps) based on its own rendered box, not the browser viewport β€” no configuration needed, and it composes the same way with Tailwind responsive prefixes in `styles` as described under [Responsive sizing](#responsive-sizing) above. +#### CardWidget -The arc's radius itself is handled separately (it's a geometry calculation, not a CSS variable) β€” it auto-fits to whatever space is left after padding and, if enabled, tick-mark space is subtracted, capped by `arc.radius` when you set one explicitly. +| Prop | Type | Description | +| --------------- | -------- | ------------------------------------------------------------------------------------ | +| `title` | `string` | Card title. Default: `"Latest Value"` | +| `unit` | `string` | Unit suffix shown next to the value | +| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | + +#### GaugeWidget + +| Prop | Type | Description | +| --------------- | --------- | -------------------------------------------------------------------------------------------------- | +| `title` | `string` | Gauge title. Default: `"Latest Value"` | +| `value` | `number` | Manual/controlled value. Used as the initial value, or the only value if no `node` is given | +| `min` | `number` | Minimum of the gauge's range. Default: `0` | +| `max` | `number` | Maximum of the gauge's range. Default: `100` | +| `unit` | `string` | Unit suffix shown next to the value | +| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | --- -#### Other props - -| Prop | Type | Description | -| --------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------- | -| `title` | `string` | Gauge title. Default: `"Latest Value"` | -| `value` | `number` | Manual/controlled value. Used as the initial value, or the only value if no `node` is given | -| `min` | `number` | Minimum of the gauge's range. Default: `0` | -| `max` | `number` | Maximum of the gauge's range. Default: `100` | -| `unit` | `string` | Unit suffix shown next to the value | -| `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | - - ## Stylesheet import This SDK ships pre-compiled CSS alongside its JavaScript β€” you don't need Tailwind configured in your own project for these widgets to render correctly, even if you don't use Tailwind at all. @@ -907,4 +993,4 @@ import "public-widget-sdk/styles.css"; That's the entire integration on your end. No `content` glob changes to your `tailwind.config`, no build coordination, nothing else required β€” every widget in this SDK will render fully styled as soon as this import is present. -> **If styles aren't appearing:** double-check the import path matches your installed package name exactly, and that it's imported somewhere that actually runs before your widgets render (e.g. not inside a conditionally-loaded file). If you're using a bundler with strict CSS module resolution, confirm it supports subpath imports from `node_modules` (most modern bundlers β€” Vite, Webpack 5+, Next.js β€” do, out of the box). +> **If styles aren't appearing:** double-check the import path matches your installed package name exactly, and that it's imported somewhere that actually runs before your widgets render (e.g. not inside a conditionally-loaded file). If you're using a bundler with strict CSS module resolution, confirm it supports subpath imports from `node_modules` (most modern bundlers β€” Vite, Webpack 5+, Next.js β€” do, out of the box). \ No newline at end of file From f92314a42446a48181e62f25a3ea826bb45c8143 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Mon, 27 Jul 2026 20:03:35 +0530 Subject: [PATCH 51/66] Update Readme.md file --- README.md | 86 ++++++++++++++++++++++++++++++++++++----- test/my-app/src/App.jsx | 1 + 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5a33a99f..ac16611f 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,8 @@ A radial arc gauge β€” shows a single value as a filled arc with an optional nee /> ``` +> **Default behaviour:** simply pass `node` and `variable` β€” the gauge renders with the light theme, title `"Latest Value"`, no tick marks, and the last‑updated label showing the current time. + #### Required props | Prop | Type | Description | @@ -417,7 +419,7 @@ If omitted, the bar falls back to the theme's `bar` slot color via `currentColor | `type` | `"line" \| "rounded" \| "drop" \| "triangle"` | `"rounded"` | Needle shape | | `length` | `"short" \| "medium" \| "full" \| number` | `"medium"` | Preset (relative to the resolved radius) or an explicit px value | | `width` | `number` | `4` | Needle thickness in px | -| `color` | `string` | β€” | Shorthand β€” sets both `needleColor` and `capColor` at once | +| `color` | `string` | `theme` | Shorthand β€” sets both `needleColor` and `capColor` at once | | `needleColor` | `string` | `color` or theme | Color of the needle shape specifically, overrides `color` for the shape only | | `capColor` | `string` | `color` or theme | Color of the center cap circle specifically | | `capRadius` | `number` | `6` | Radius of the center cap circle in px | @@ -462,11 +464,11 @@ Setting `needle={{ show: false }}` turns the gauge into a donut-style indicator | `show` | `boolean` | `false` | Whether tick marks are drawn | | `count` | `number` | `10` | Number of **intervals** between `min` and `max` β€” `count: 10` draws 11 marks | | `size` | `number` | `6` | Tick line length in px | -| `color` | `string` | β€” | Tick line color; falls back to the theme's `tick` slot via `currentColor` | +| `color` | `string` | `theme` | Tick line color; falls back to the theme's `tick` slot via `currentColor` | | `radiusOffset` | `number` | `4` | Gap in px between the arc's outer edge and the start of the tick line | | `labelGap` | `number` | `4` | Gap in px between the end of the tick line and its label | | `labelSize` | `number` | `10` | Tick label font size in px β€” set as an inline style, so it always wins over `styles.tickLabel` | -| `labelColor` | `string` | β€” | Tick label color; falls back to the theme's `tickLabel` slot | +| `labelColor` | `string` | `theme` | Tick label color; falls back to the theme's `tickLabel` slot | | `labelFormat` | `(value: number) => string` | β€” | Custom formatter for tick numbers. If omitted, reuses the widget's `format` preset if one is set, otherwise a plain rounded number | Enabling ticks reserves extra space inside the widget for the line + gaps + label, shrinking the arc's radius slightly so the ring is never clipped β€” you don't need to size the container any differently to accommodate it. @@ -487,7 +489,7 @@ Enabling ticks reserves extra space inside the widget for the line + gaps + labe | ---------- | ------------- | ------------ | -------------------------------------------------------------- | | `show` | `boolean` | `true` | Whether the bar (and needle, if also enabled) animates | | `duration` | `number` | `1000` | Transition duration in ms | -| `easing` | `GaugeEasing` | `"cubicOut"` | Any of the standard d3-ease families β€” `linear`, `quadIn/Out/InOut`, `cubicIn/Out/InOut`, `sinIn/Out/InOut`, `expIn/Out/InOut`, `circleIn/Out/InOut`, `backIn/Out/InOut`, `elasticIn/Out/InOut`, `bounceIn/Out/InOut` | +| `easing` | `GaugeEasing` | `"cubicOut"` | Any of the standard d3-ease families β€” `easeLinear`, `easeQuadIn`, `easeQuadOut`, `easeQuadInOut`, `easeCubicIn`, `easeCubicOut`, `easeCubicInOut`, `easeSinIn`, `easeSinOut`, `easeSinInOut`, `easeExpIn`, `easeExpOut`, `easeExpInOut`, `easeCircleIn`, `easeCircleOut`, `easeCircleInOut`, `easeBackIn`, `easeBackOut`, `easeBackInOut`, `easeElasticIn`, `easeElasticOut`, `easeElasticInOut`, `easeBounceIn`, `easeBounceOut`, `easeBounceInOut` | With `animation.show: false`, both the bar and needle snap directly to the new value with no transition, regardless of `needle.animation`. @@ -497,16 +499,70 @@ With `animation.show: false`, both the bar and needle snap directly to the new v `onDataChange` works the same way it does on `CardWidget` (see [`onDataChange` under CardWidget](#ondatachange--data-driven-rendering)) β€” it's called with the latest fetched reading and a `meta` object, and can return a partial set of props (including `styles`) that temporarily override the gauge's own props: +**Example 1 – change many props based on value ranges** + ```tsx { + if (!data || meta.kind !== "success") return; + + if (data.value > 80) { + return { + title: "πŸ”΄ High", + color: "#ef4444", + theme: "dark", + arc: { startAngle: -135, endAngle: 135 }, + needle: { type: "triangle", color: "#dc2626" }, + animation: { duration: 500, easing: "elasticOut" }, + tick: { show: true, color: "#fca5a5", labelColor: "#f87171" }, + styles: { + value: "text-red-500 text-4xl font-black", + title: "uppercase tracking-wide", + }, + }; + } + if (data.value < 20) { + return { + title: "🟒 Low", + color: ["#10b981", "#34d399"], + arc: { thickness: 18 }, + needle: { show: false }, + }; + } + // Clear overrides for mid-range values + }} +/> +``` + +**Example 2 – custom error and empty rendering** + +```tsx + { if (meta.kind === "error") { - return { renderError: () => Offline }; + return { + renderError: (msg) => ( +
+ ⚠️ + {msg} +
+ ), + }; } - if (!data) return; - if (data.value > 80) { - return { color: "#ef4444", theme: "dark" }; + if (meta.kind === "empty") { + return { + renderEmpty: () => ( + β€” waiting for first reading β€” + ), + }; } + // No override on success }} /> ``` @@ -661,9 +717,11 @@ By default, the label under the value shows a fixed clock time (`"Updated 14:32: ```tsx +// commonProps = { node, variable: "humidity" } // shows the timestamp converted to Eastern time, regardless of the visitor's own browser timezone +// commonProps = { node, variable: "humidity" } // shows the timestamp converted to Indian Standard Time ``` @@ -677,12 +735,15 @@ If omitted, the widget uses `Intl.DateTimeFormat().resolvedOptions().timeZone` ```tsx +// commonProps = { node, variable: "humidity" } // "5 minutes ago" instead of "Updated 14:32:10" +// commonProps = { node, variable: "humidity" } // "Updated 7/24/2026" +// commonProps = { node, variable: "humidity" } // "5 minutes ago" instead of "Updated 14:32:10" ``` @@ -752,6 +813,8 @@ Both `error` and `empty` are real slots, so they pick up theme colors automatica empty: "text-slate-300", }} /> + +//commonProps = { node, variable: "humidity" } ``` #### `renderError` / `renderEmpty` β€” full custom rendering @@ -780,6 +843,8 @@ For full control beyond just restyling text, `renderError` and `renderEmpty` let )} renderEmpty={() => β€” no reading yet β€”} /> + +// commonProps = { node, variable: "humidity" } ``` `renderError` receives the raw error message string; `renderEmpty` takes no arguments. When either is provided, it fully replaces the default `error`/`empty` slot rendering β€” the corresponding `styles.error`/`styles.empty` classes are ignored in that case, since there's no default element left for them to apply to. @@ -820,6 +885,8 @@ For full control beyond just restyling text, `renderError` and `renderEmpty` let } }} /> + +// commonProps = { node, variable: "humidity" } ``` `meta.kind` is one of `"success"`, `"error"`, or `"empty"`; `meta.error` is present only when `meta.kind === "error"`, carrying the underlying error message. @@ -907,10 +974,11 @@ By default the following properties scale automatically: - unit font size - label font size - spacing (`gap`) +- arc thickness (gauge bar thickness) **When `height` is omitted**, scaling responds to the container's **width only** (`cqw`). -**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size container renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. +**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size container renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. For the `GaugeWidget`, the arc radius and thickness are also computed from the available container size, so they resize automatically. A widget inside a narrow dashboard column will use smaller typography than the same widget rendered full-width, even on the same screen β€” this behavior is built in and needs no configuration. diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index f2f602b0..6377960c 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -498,6 +498,7 @@ export default function App() { }} size={400} /> +
); From 6d894812ffb534069c5420b86cd9c30245c69b00 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Tue, 28 Jul 2026 10:30:58 +0530 Subject: [PATCH 52/66] application exmaple --- application-examples/my-app/.env.example | 3 + application-examples/my-app/.gitignore | 25 + application-examples/my-app/README.md | 18 + application-examples/my-app/eslint.config.js | 29 + application-examples/my-app/index.html | 13 + application-examples/my-app/package-lock.json | 4281 +++++++++++++++++ application-examples/my-app/package.json | 36 + .../my-app/public/favicon.svg | 1 + application-examples/my-app/public/icons.svg | 24 + application-examples/my-app/src/App.css | 184 + application-examples/my-app/src/App.jsx | 332 ++ application-examples/my-app/src/Test.tsx | 1335 +++++ .../my-app/src/assets/hero.png | Bin 0 -> 44919 bytes .../my-app/src/assets/react.svg | 1 + .../my-app/src/assets/vite.svg | 1 + application-examples/my-app/src/globals.css | 54 + application-examples/my-app/src/index.css | 113 + application-examples/my-app/src/main.jsx | 10 + application-examples/my-app/vite.config.js | 24 + test/my-app/src/App.jsx | 7 - 20 files changed, 6484 insertions(+), 7 deletions(-) create mode 100644 application-examples/my-app/.env.example create mode 100644 application-examples/my-app/.gitignore create mode 100644 application-examples/my-app/README.md create mode 100644 application-examples/my-app/eslint.config.js create mode 100644 application-examples/my-app/index.html create mode 100644 application-examples/my-app/package-lock.json create mode 100644 application-examples/my-app/package.json create mode 100644 application-examples/my-app/public/favicon.svg create mode 100644 application-examples/my-app/public/icons.svg create mode 100644 application-examples/my-app/src/App.css create mode 100644 application-examples/my-app/src/App.jsx create mode 100644 application-examples/my-app/src/Test.tsx create mode 100644 application-examples/my-app/src/assets/hero.png create mode 100644 application-examples/my-app/src/assets/react.svg create mode 100644 application-examples/my-app/src/assets/vite.svg create mode 100644 application-examples/my-app/src/globals.css create mode 100644 application-examples/my-app/src/index.css create mode 100644 application-examples/my-app/src/main.jsx create mode 100644 application-examples/my-app/vite.config.js diff --git a/application-examples/my-app/.env.example b/application-examples/my-app/.env.example new file mode 100644 index 00000000..ec1a2dc6 --- /dev/null +++ b/application-examples/my-app/.env.example @@ -0,0 +1,3 @@ +VITE_CARD_WIDGET_TOKEN_ID="your_token_id_here" +VITE_CARD_WIDGET_TOKEN="your_token_secret_here" +VITE_CARD_WIDGET_NODE_ID="your_node_id_here" \ No newline at end of file diff --git a/application-examples/my-app/.gitignore b/application-examples/my-app/.gitignore new file mode 100644 index 00000000..7ceb59f8 --- /dev/null +++ b/application-examples/my-app/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.env diff --git a/application-examples/my-app/README.md b/application-examples/my-app/README.md new file mode 100644 index 00000000..e16d995e --- /dev/null +++ b/application-examples/my-app/README.md @@ -0,0 +1,18 @@ +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) + +## React Compiler + +The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. + +Note: This will impact Vite dev & build performances. + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/application-examples/my-app/eslint.config.js b/application-examples/my-app/eslint.config.js new file mode 100644 index 00000000..4fa125da --- /dev/null +++ b/application-examples/my-app/eslint.config.js @@ -0,0 +1,29 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import { defineConfig, globalIgnores } from 'eslint/config' + +export default defineConfig([ + globalIgnores(['dist']), + { + files: ['**/*.{js,jsx}'], + extends: [ + js.configs.recommended, + reactHooks.configs.flat.recommended, + reactRefresh.configs.vite, + ], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + parserOptions: { + ecmaVersion: 'latest', + ecmaFeatures: { jsx: true }, + sourceType: 'module', + }, + }, + rules: { + 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], + }, + }, +]) diff --git a/application-examples/my-app/index.html b/application-examples/my-app/index.html new file mode 100644 index 00000000..53beb493 --- /dev/null +++ b/application-examples/my-app/index.html @@ -0,0 +1,13 @@ + + + + + + + my-app + + +
+ + + diff --git a/application-examples/my-app/package-lock.json b/application-examples/my-app/package-lock.json new file mode 100644 index 00000000..53d391c0 --- /dev/null +++ b/application-examples/my-app/package-lock.json @@ -0,0 +1,4281 @@ +{ + "name": "my-app", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "my-app", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/material": "^9.2.0", + "public-widget-sdk": "file:../../", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@babel/core": "^7.29.0", + "@eslint/js": "^9.39.4", + "@rolldown/plugin-babel": "^0.2.1", + "@tailwindcss/vite": "^4.3.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "babel-plugin-react-compiler": "^1.0.0", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "tailwindcss": "^4.3.3", + "vite": "^8.0.1" + } + }, + "../..": { + "name": "public-widget-sdk", + "version": "5.5.0", + "license": "ISC", + "dependencies": { + "@anedyasystems/anedya-frontend-sdk": "^0.1.1", + "@types/d3": "^7.4.3", + "clsx": "^2.1.1", + "d3": "^7.9.0", + "tailwind-merge": "^3.6.0" + }, + "devDependencies": { + "@base-ui/react": "^1.6.0", + "@tailwindcss/cli": "^4.3.3", + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.3.2", + "tsdown": "^0.22.13", + "typescript": "^5.7.3" + }, + "peerDependencies": { + "@base-ui/react": "^1.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", + "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.3.0", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", + "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-9.2.0.tgz", + "integrity": "sha512-+XMav+ZaXkZKUFUgzjrfMEedfyJKxxviAske2q8N8CWDMeqZdDU2lWMkiUPiB388hGaDqhwvOAwkrsc/pUyp8g==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/material": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.2.0.tgz", + "integrity": "sha512-+YTRSgGKGrrRo2XJZXs7JRA6qHoHWvNtxyqxnrRJTBmIuLOUpxxh7m4G9lF4tWberxGFY+EqkkRPgJCl+fSMJg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/core-downloads-tracker": "^9.2.0", + "@mui/system": "^9.2.0", + "@mui/types": "^9.1.1", + "@mui/utils": "^9.2.0", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.12", + "clsx": "^2.1.1", + "csstype": "^3.2.3", + "prop-types": "^15.8.1", + "react-is": "^19.2.6", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^9.2.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-9.2.0.tgz", + "integrity": "sha512-w9wpyDxGPGnAACPB2hKhCDmILJIAvQxrfjUbIAEa0AznX1rOjaz5N+yB1uuw8ixnJcpEh/tPbD9oEe19wcWPHw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/utils": "^9.2.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-9.1.1.tgz", + "integrity": "sha512-neaYKdJfvEG54q8efHLJR7swpHG/gfSv9xGqW5iTSMsubD7yPCPFrhVBt284j1DOF3uZaaDJSHQL7gz6jGF21Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "csstype": "^3.2.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-9.2.0.tgz", + "integrity": "sha512-YvUJwKoGVtbnOm2PyPi5TvX2d1rOA6sqSpEWVs4WmXNIaFTuYmNUaVdU2o1NKUEe31URnD3E8ZVUMcsLQXwcYg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/private-theming": "^9.2.0", + "@mui/styled-engine": "^9.1.1", + "@mui/types": "^9.1.1", + "@mui/utils": "^9.2.0", + "clsx": "^2.1.1", + "csstype": "^3.2.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.1.1.tgz", + "integrity": "sha512-Zjt7u8wNvDg40rPTGoL+TnfkpuSKjwubsNSFRH1KAVZLcaV4I3AFNHIFbvH7p4F3alEibSbdd90xAgn5Rnfndg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.2.0.tgz", + "integrity": "sha512-OsUH5zhlSOM4xmLl53+agug1M1UyWb4zxFxWQCqwKTKUeQPvTENtg3JhrroBD2qpCLKsX5W/DYGERJ4mBUbc8g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "@mui/types": "^9.1.1", + "@types/prop-types": "^15.7.15", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.2.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.140.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", + "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", + "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", + "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", + "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", + "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", + "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", + "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", + "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", + "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", + "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", + "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", + "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", + "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.2", + "@emnapi/runtime": "1.11.2", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", + "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", + "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/plugin-babel": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.3.tgz", + "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=22.12.0 || ^24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.29.0 || ^8.0.0-rc.1", + "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", + "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", + "rolldown": "^1.0.0-rc.5", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@babel/plugin-transform-runtime": { + "optional": true + }, + "@babel/runtime": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/node/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", + "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "tailwindcss": "4.3.3" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7 || ^8" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.12", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", + "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.4.tgz", + "integrity": "sha512-XcCQz0TBpBgljhj0gMuuDj49i6Ytqh5q1osT/Gp5uAVJUCTWxyskk/l1jwYYiu2xcNHHipdMz40EGfM1VdamVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.1.tgz", + "integrity": "sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.395", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", + "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.24.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", + "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.5", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", + "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.6", + "@eslint/js": "9.39.5", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.3.tgz", + "integrity": "sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": "^9 || ^10" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", + "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", + "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", + "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/public-widget-sdk": { + "resolved": "../..", + "link": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", + "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", + "license": "MIT" + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rolldown": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", + "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@oxc-project/types": "=0.140.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.0", + "@rolldown/binding-darwin-arm64": "1.2.0", + "@rolldown/binding-darwin-x64": "1.2.0", + "@rolldown/binding-freebsd-x64": "1.2.0", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", + "@rolldown/binding-linux-arm64-gnu": "1.2.0", + "@rolldown/binding-linux-arm64-musl": "1.2.0", + "@rolldown/binding-linux-ppc64-gnu": "1.2.0", + "@rolldown/binding-linux-s390x-gnu": "1.2.0", + "@rolldown/binding-linux-x64-gnu": "1.2.0", + "@rolldown/binding-linux-x64-musl": "1.2.0", + "@rolldown/binding-openharmony-arm64": "1.2.0", + "@rolldown/binding-wasm32-wasi": "1.2.0", + "@rolldown/binding-win32-arm64-msvc": "1.2.0", + "@rolldown/binding-win32-x64-msvc": "1.2.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", + "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.17", + "rolldown": "~1.1.5", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@emnapi/core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/vite/node_modules/@oxc-project/types": { + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/rolldown": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + } + } +} diff --git a/application-examples/my-app/package.json b/application-examples/my-app/package.json new file mode 100644 index 00000000..69feefbc --- /dev/null +++ b/application-examples/my-app/package.json @@ -0,0 +1,36 @@ +{ + "name": "my-app", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/material": "^9.2.0", + "public-widget-sdk": "file:../../", + "react": "^19.2.4", + "react-dom": "^19.2.4" + }, + "devDependencies": { + "@babel/core": "^7.29.0", + "@eslint/js": "^9.39.4", + "@rolldown/plugin-babel": "^0.2.1", + "@tailwindcss/vite": "^4.3.3", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "babel-plugin-react-compiler": "^1.0.0", + "eslint": "^9.39.4", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.5.2", + "globals": "^17.4.0", + "tailwindcss": "^4.3.3", + "vite": "^8.0.1" + } +} diff --git a/application-examples/my-app/public/favicon.svg b/application-examples/my-app/public/favicon.svg new file mode 100644 index 00000000..6893eb13 --- /dev/null +++ b/application-examples/my-app/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/application-examples/my-app/public/icons.svg b/application-examples/my-app/public/icons.svg new file mode 100644 index 00000000..e9522193 --- /dev/null +++ b/application-examples/my-app/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/application-examples/my-app/src/App.css b/application-examples/my-app/src/App.css new file mode 100644 index 00000000..f90339d8 --- /dev/null +++ b/application-examples/my-app/src/App.css @@ -0,0 +1,184 @@ +.counter { + font-size: 16px; + padding: 5px 10px; + border-radius: 5px; + color: var(--accent); + background: var(--accent-bg); + border: 2px solid transparent; + transition: border-color 0.3s; + margin-bottom: 24px; + + &:hover { + border-color: var(--accent-border); + } + &:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } +} + +.hero { + position: relative; + + .base, + .framework, + .vite { + inset-inline: 0; + margin: 0 auto; + } + + .base { + width: 170px; + position: relative; + z-index: 0; + } + + .framework, + .vite { + position: absolute; + } + + .framework { + z-index: 1; + top: 34px; + height: 28px; + transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) + scale(1.4); + } + + .vite { + z-index: 0; + top: 107px; + height: 26px; + width: auto; + transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) + scale(0.8); + } +} + +#center { + display: flex; + flex-direction: column; + gap: 25px; + place-content: center; + place-items: center; + flex-grow: 1; + + @media (max-width: 1024px) { + padding: 32px 20px 24px; + gap: 18px; + } +} + +#next-steps { + display: flex; + border-top: 1px solid var(--border); + text-align: left; + + & > div { + flex: 1 1 0; + padding: 32px; + @media (max-width: 1024px) { + padding: 24px 20px; + } + } + + .icon { + margin-bottom: 16px; + width: 22px; + height: 22px; + } + + @media (max-width: 1024px) { + flex-direction: column; + text-align: center; + } +} + +#docs { + border-right: 1px solid var(--border); + + @media (max-width: 1024px) { + border-right: none; + border-bottom: 1px solid var(--border); + } +} + +#next-steps ul { + list-style: none; + padding: 0; + display: flex; + gap: 8px; + margin: 32px 0 0; + + .logo { + height: 18px; + } + + a { + color: var(--text-h); + font-size: 16px; + border-radius: 6px; + background: var(--social-bg); + display: flex; + padding: 6px 12px; + align-items: center; + gap: 8px; + text-decoration: none; + transition: box-shadow 0.3s; + + &:hover { + box-shadow: var(--shadow); + } + .button-icon { + height: 18px; + width: 18px; + } + } + + @media (max-width: 1024px) { + margin-top: 20px; + flex-wrap: wrap; + justify-content: center; + + li { + flex: 1 1 calc(50% - 8px); + } + + a { + width: 100%; + justify-content: center; + box-sizing: border-box; + } + } +} + +#spacer { + height: 88px; + border-top: 1px solid var(--border); + @media (max-width: 1024px) { + height: 48px; + } +} + +.ticks { + position: relative; + width: 100%; + + &::before, + &::after { + content: ''; + position: absolute; + top: -4.5px; + border: 5px solid transparent; + } + + &::before { + left: 0; + border-left-color: var(--border); + } + &::after { + right: 0; + border-right-color: var(--border); + } +} diff --git a/application-examples/my-app/src/App.jsx b/application-examples/my-app/src/App.jsx new file mode 100644 index 00000000..52b3c89a --- /dev/null +++ b/application-examples/my-app/src/App.jsx @@ -0,0 +1,332 @@ +import React from "react"; +import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; +import { CardWidget } from "../../../src"; +import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; +import "public-widget-sdk/styles.css"; +import "./index.css"; + +// This demo has its own Tailwind build (see vite.config.js + src/index.css), +// specifically to test consumer-side class overrides via `className`/`styles`. +// A real consumer app needs the same setup β€” the widget package's own +// precompiled stylesheet only covers its built-in default classes, not +// arbitrary classes a consumer passes in. + +const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; +const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; +const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; + +const anedya = new Anedya(); +const config = anedya.newConfig(tokenId, token); +const client = anedya.newClient(config); +const node = anedya.newNode(client, nodeId); + +// Shared node/variable pair reused across most examples below. +const commonProps = { node, variable: "humidity" }; + +// ============================================================ +// Reusable theme objects β€” shareable across every widget instance +// that uses them. Only specify the slots you actually want to change +// from the built-in default; anything omitted falls back to the +// light/dark preset. +// ============================================================ + +/** A custom CardWidget theme. */ +const emeraldCardTheme = { + styles: { + container: "bg-emerald-50 border-emerald-200", + title: "text-emerald-700", + value: "text-emerald-900", + label: "text-emerald-500", + }, +}; + +/** + * A custom GaugeWidget theme. + * + * Note the two different color formats in play: + * - `container`/`title`/`value`/`label` are Tailwind classes, since those + * slots render as normal HTML elements. + * - `track`/`bar`/`needle`/`needleCap` accept hex colors OR Tailwind + * `text-*` classes (read via `currentColor`), since those slots render + * as SVG elements drawn by D3, not plain HTML. + */ +const emeraldGaugeTheme = { + styles: { + container: "bg-emerald-50 border-emerald-200", + title: "text-emerald-800", + value: "text-emerald-950", + label: "text-emerald-600", + + track: "#E2E8F0", // hex color, applied directly + bar: "#10B981", + needle: "#047857", + needleCap: "#065F46", + }, +}; + +export default function App() { + return ( +
+ {/* ================================================================ + * SECTION 1 β€” CardWidget + * ================================================================ */} + + {/* ---------------------------------------------------------------- + * 1.1 Default appearance β€” no theme, no styles, no formatting + * props. Every built-in fallback in one place. + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 1.2 theme β€” a reusable, shareable WidgetTheme object. Same + * effect across every widget instance that uses it. Built-in + * preset names ("light" / "dark") also work directly. + * ---------------------------------------------------------------- */} + + + + {/* ---------------------------------------------------------------- + * 1.3 styles vs className β€” the distinction that matters most: + * + * - `styles` (object): per-SLOT overrides. Keys are + * "container" | "title" | "value" | "unit" | "label" + * ("error"/"empty" too β€” see 1.5) β€” reach INSIDE the widget. + * + * - `className` (string): the ordinary React convention β€” one + * class applied ONLY to the widget's outermost container. + * Merged (via twMerge) with whatever styles.container already + * resolved to, not a replacement for it. + * + * IMPORTANT: any class you pass here (Tailwind or otherwise) must + * already exist in YOUR app's own compiled CSS β€” the widget's + * precompiled stylesheet only covers its own built-in classes. + * This demo has its own Tailwind build for exactly this reason. + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 1.4 formatValue / format / labelText / labelFormat β€” see README + * "Formatting vs rendering" and "The last-updated label" sections + * for the full precedence rules. formatValue/labelText are full + * escape hatches; format/labelFormat are zero-code presets. + * ---------------------------------------------------------------- */} + `${v.toFixed(2)} % RH`} + labelFormat="relative" + /> + + {/* ---------------------------------------------------------------- + * 1.5 Error & empty states β€” onDataChange's second argument + * (`meta`) tells you which state just occurred, so you can swap in + * fully custom JSX via renderError/renderEmpty. See README "Error + * & empty states" for the full behavior and styles.error/empty. + * ---------------------------------------------------------------- */} + { + if (meta.kind === "error") { + return { + renderError: () => ( + Sensor unreachable + ), + }; + } + if (meta.kind === "empty") { + return { + renderEmpty: () => ( + β€” no reading yet β€” + ), + }; + } + }} + /> + + {/* ---------------------------------------------------------------- + * 1.6 onDataChange β€” conditional overrides driven by the RAW + * fetched data ({ value, timestamp }), applied on top of + * everything else (theme, styles, className). + * ---------------------------------------------------------------- */} + { + if (!data) return; + if (data.value > 80) { + return { title: "High Humidity", theme: "dark", styles: { value: "text-red-500" } }; + } + return { title: "Humidity", theme: "light" }; + }} + /> + + {/* ---------------------------------------------------------------- + * 1.7 Sizing β€” width/height/minWidth/maxWidth are plain props, + * applied as inline styles on the container. See README "Sizing" + * β€” `height` has two distinct modes (auto-grow vs. fixed+clip). + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 1.8 timezone β€” pins the last-updated label to a specific IANA + * timezone instead of the visitor's auto-detected one. + * ---------------------------------------------------------------- */} + + + {/* ================================================================ + * SECTION 2 β€” GaugeWidget + * ================================================================ */} + + {/* ---------------------------------------------------------------- + * 2.1 Default appearance β€” live data, no theme/styling overrides. + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 2.2 Manual value mode β€” pass `value` directly instead of `node`/ + * `variable` for a static/controlled gauge (e.g. driven by your + * own app state rather than live Anedya data). + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 2.3 Full arc/track/needle/color/tick configuration, plus a + * custom theme. Demonstrates most visual knobs at once. + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 2.4 onDataChange β€” same pattern as CardWidget: conditional + * overrides (title, color, needle color, track color, animation + * speed) driven by the raw fetched value. + * ---------------------------------------------------------------- */} + { + if (!data) return; + const isCritical = data.value > 70; + const isWarning = data.value > 40 && data.value <= 60; + + return { + title: isCritical ? "Critical" : isWarning ? "Warning" : "Normal", + color: isCritical ? "#ef4444" : isWarning ? "#f59e0b" : "#10b981", + needle: { needleColor: isCritical ? "#ef4444" : "#10b981" }, + animation: { duration: isCritical ? 400 : 1000 }, + styles: { + value: isCritical ? "text-red-500 animate-pulse" : undefined, + }, + }; + }} + /> + + {/* ---------------------------------------------------------------- + * 2.5 formatValue / labelText β€” full custom formatting, same + * relationship to format/labelFormat as CardWidget. + * ---------------------------------------------------------------- */} + `${v} km/h`} + labelText={(ts) => `Refreshed at ${new Date(ts).toLocaleTimeString()}`} + /> + + {/* ---------------------------------------------------------------- + * 2.6 Per-slot styles β€” including the SVG-backed slots + * (track/bar/needle/needleCap/tick/tickLabel), which accept hex + * colors or `text-*` Tailwind classes (read via currentColor). + * ---------------------------------------------------------------- */} + + + {/* ---------------------------------------------------------------- + * 2.7 Error & empty states β€” identical mechanism to CardWidget. + * ---------------------------------------------------------------- */} + ( +
+ ⚠ Sensor unreachable + {error} +
+ )} + renderEmpty={() => β€” no reading yet β€”} + /> + + {/* ---------------------------------------------------------------- + * 2.8 timezone β€” same as CardWidget's. + * ---------------------------------------------------------------- */} + +
+ ); +} \ No newline at end of file diff --git a/application-examples/my-app/src/Test.tsx b/application-examples/my-app/src/Test.tsx new file mode 100644 index 00000000..da9c986f --- /dev/null +++ b/application-examples/my-app/src/Test.tsx @@ -0,0 +1,1335 @@ +// import React from "react"; +// import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; +// import { CardWidget } from "../../../src"; +// import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; +// import "../../../dist/styles.css"; + +// import { relativeTime } from "../../../src/helpers/formatters"; +// const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; +// const token = +// "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; +// const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; + +// const anedya = new Anedya(); +// const config = anedya.newConfig(tokenId, token); +// const client = anedya.newClient(config); +// const node = anedya.newNode(client, nodeId); + +// /** +// * A reusable theme, shareable across every CardWidget instance in your +// * app. Only specify the slots you actually want to change from the +// * built-in default β€” anything omitted falls back to lightTheme/darkTheme. +// */ +// const emeraldTheme = { +// classNames: { +// container: "bg-emerald-50 border-emerald-200", +// title: "text-emerald-700", +// value: "text-emerald-900", +// label: "text-emerald-500", +// }, +// }; + + +// const commonProps = { node, variable: "humidity" }; + +// export default function App() { +// return ( + +//
+ +// `Last synced ${relativeTime(ts)}`} + +// /> + + +// {/* ============================================================ +// * 2. theme β€” a reusable, shareable WidgetTheme object. Same +// * effect across every widget instance that uses it. +// * ============================================================ */} +// + +// {/* Built-in preset names also work directly: */} +// + +// {/* ============================================================ +// * 3. styles vs className β€” THE distinction to understand: +// * +// * - `styles` (plural, an OBJECT): per-SLOT overrides. +// * Keys are "container" | "title" | "value" | "unit" | "label" +// * β€” lets you reach INSIDE the widget and style individual +// * pieces independently. +// * +// * - `className` (singular, a STRING): the ordinary React +// * convention β€” one class applied ONLY to the widget's +// * outermost container element, same as you'd pass to any +// * other component. It's merged (via twMerge) with whatever +// * styles.container already resolved to, not a +// * replacement for it. +// * +// * This example uses BOTH at once so the difference is visible: +// * className adds a shadow to the outer box, styles.value/ +// * styles.title style two INNER pieces independently. +// * ============================================================ */} +// + +// {/* ============================================================ +// * 4. Plain CSS classes β€” styles works with ANY class source, +// * not just Tailwind. These reference plain hand-written CSS +// * classes (e.g. defined in a .css file this app already imports). +// * ============================================================ */} +// {/* */} + +// {/* ============================================================ +// * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` +// * work exactly as they do anywhere else in your app, because +// * styles just forwards whatever string you write straight +// * to `className`. This widget does NOT have its own custom +// * breakpoint system β€” these prefixes are compiled by YOUR +// * project's Tailwind config and respond to the BROWSER VIEWPORT, +// * same as native Tailwind everywhere else. If your own +// * tailwind.config.js customizes `theme.screens`, these prefixes +// * automatically follow that customization too β€” nothing to +// * configure on the widget's side. +// * ============================================================ */} +// {/* */} + +// {/* ============================================================ +// * 6. formatValue / labelText β€” simple formatting hooks, distinct +// * from styling. formatValue controls the displayed number's +// * text; labelText controls the caption under it. +// * ============================================================ */} +// {/* `${v.toFixed(2)} % RH`} +// labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} + +// /> */} + +// {/* ============================================================ +// * 7. onStyleChange β€” conditional class overrides driven by the +// * RAW fetched data ({ value, timestamp }), always applied on top +// * of everything else (theme, styles, className). +// * ============================================================ */} +// {/* { +// if (!data) return; + +// if (data.value > 80) { +// return { +// title: "High Humidity", +// theme: "dark", +// styles: { +// value: "text-red-500" +// } +// }; +// } + +// return { +// title: "Humidity", +// theme: "light" +// }; +// }} + +// /> */} + +// {/* ============================================================ +// * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, +// * applied as inline styles on the container, independent of the +// * whole styles/theme system. +// * ============================================================ */} +// {/* */} + + +// {/* { +// // "Hello"; +// // }, +// // }} +// // labels={{ +// // show: true, +// // position: "outside", +// // }} +// // scale={{ +// // minLabel: "Hello", +// // maxLabel: "World", +// // }} +// // ticks={{ +// // show: true, +// // count: 10, +// // position: "outside", +// // length: 10, +// // labels: true, +// // }} +// animation={{ +// duration: 4000, +// easing: "easeElasticOut", // easeCubicOut, easeElasticOut +// }} +// // tooltip={{ +// // show:false, +// // }} +// // classNames={{ +// // title: "text-white", +// // tickLabel: "text-white text-lg", +// // label: "text-red", +// // value: "text-white", +// // }} +// theme="dark" +// /> */} + +// + +// + +// +// style={{ +// backgroundColor: "#1e1e2f", +// borderRadius: "16px", +// padding: "10px", +// }} +// // 'styles' affects specific internal SVG/HTML slots via Tailwind classes +// styles={{ +// container: "border border-gray-700", // merges with outer wrapper +// title: "text-purple-400 text-xs uppercase tracking-wider", +// value: "text-white text-2xl font-mono", +// unit: "text-gray-400 text-sm", +// label: "text-gray-500 text-[10px]", +// bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients +// needle: "stroke-pink-400 stroke-2", +// needleCap: "fill-pink-400", +// }} +// /> + +// + +// + +// + +// {/* // 1. Show a custom static text */} +// "Last reading"} // Always shows "Last reading" +// /> + +// {/* // 2. Format the timestamp exactly how you want */} +// +// `Updated at ${new Date(timestamp).toLocaleString("en-US", { +// hour: "2-digit", +// minute: "2-digit", +// second: "2-digit", +// })}` +// } +// // Output: "Updated at 02:30:45 PM" +// /> + +// {/* // 3. Show relative time with custom wording */} +// { +// const diff = Math.floor((Date.now() - timestamp) / 60000); +// if (diff < 1) return "Just now"; +// if (diff < 60) return `${diff} min ago`; +// return `${Math.floor(diff / 60)} hours ago`; +// }} +// /> + +// {/* // 4. Hide the label entirely (return null or empty string) */} +// null} // No label shown +// /> +//
+// ); +// } + +{ + /* +//create react app +//link public-widget-sdk +//npm run dev +//send this file tp yash to copy paste */ +} + + + +// import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +// import * as d3 from "d3"; +// import { twMerge } from "tailwind-merge"; +// import { AnedyaWidgetBaseProps } from "../../common"; +// import { SlotClassNames, WidgetTheme } from "../../types/root"; +// import { +// GaugeAnimationConfig, +// GaugeArcConfig, +// GaugeBarSpec, +// GaugeColor, +// GaugeLabelsConfig, +// GaugeNeedleConfig, +// GaugeNeedleLabelConfig, +// GaugeScaleConfig, +// GaugeSegment, +// GaugeSlot, +// GaugeThreshold, +// GaugeTicksConfig, +// GaugeTooltipConfig, +// GaugeTrackConfig, +// GaugeValueLabelConfig, +// GaugeVariant, +// } from "../../types/gauge"; +// import { +// DEFAULT_GAUGE_THEME, +// GAUGE_DEFAULT_CLASSES, +// gaugeDarkTheme, +// gaugeLightTheme, +// } from "../../themes/gaugeTheme"; +// import { useResizeObserver } from "../../hooks/useResizeObserver"; + +// export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { +// variant?: GaugeVariant; +// /** Used before live data arrives, or standalone in dummy-data mode. */ +// value?: number; +// min?: number; +// max?: number; +// size?: number; +// responsive?: boolean; + +// arc?: GaugeArcConfig; +// track?: GaugeTrackConfig; +// fillMode?: "progress" | "solid"; +// /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ +// color?: GaugeColor; +// bars?: GaugeBarSpec[]; + +// needle?: GaugeNeedleConfig; +// labels?: GaugeLabelsConfig; +// valueLabel?: GaugeValueLabelConfig; +// needleLabel?: GaugeNeedleLabelConfig; +// scale?: GaugeScaleConfig; +// ticks?: GaugeTicksConfig; +// segments?: GaugeSegment[]; +// thresholds?: GaugeThreshold[]; +// animation?: GaugeAnimationConfig; +// tooltip?: GaugeTooltipConfig; + +// classNames?: SlotClassNames; +// style?: React.CSSProperties; + +// onClick?: (value: number) => void; +// onHover?: (value: number | null) => void; +// onValueChange?: (value: number) => void; +// } + +// const DEG2RAD = Math.PI / 180; + +// const DEFAULT_ARC: Required> = { +// startAngle: -90, +// endAngle: 90, +// cornerRadius: 0, +// gap: 6, +// }; + +// const DEFAULT_ANIMATION: Required = { +// duration: 750, +// easing: "easeCubicOut", +// }; + +// function resolveEase(name: string) { +// return (d3 as any)[name] ?? d3.easeCubicOut; +// } + +// function needlePixelLength( +// length: GaugeNeedleConfig["length"], +// radius: number +// ) { +// if (typeof length === "number") return length; +// switch (length) { +// case "short": +// return radius * 0.55; +// case "full": +// return radius * 0.95; +// case "medium": +// default: +// return radius * 0.75; +// } +// } + +// /** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ +// function needleShape( +// type: NonNullable, +// length: number, +// width: number +// ) { +// const w = width; +// switch (type) { +// case "line": +// return { +// tag: "line", +// attrs: { +// x1: 0, +// y1: 0, +// x2: 0, +// y2: -length, +// strokeWidth: w, +// strokeLinecap: "butt", +// }, +// }; +// case "rounded": +// return { +// tag: "line", +// attrs: { +// x1: 0, +// y1: 0, +// x2: 0, +// y2: -length, +// strokeWidth: w, +// strokeLinecap: "round", +// }, +// }; +// case "triangle": { +// const half = w / 2; +// return { +// tag: "polygon", +// attrs: { +// points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ +// -length * 0.15 +// }`, +// }, +// }; +// } +// case "drop": +// default: { +// const half = w / 2; +// // Teardrop: rounded base, sharp tip. +// const d = `M ${-half} 0 +// C ${-half} ${-length * 0.35}, ${-w} ${ +// -length * 0.7 +// }, 0 ${-length} +// C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 +// A ${half} ${half} 0 1 1 ${-half} 0 Z`; +// return { tag: "path", attrs: { d } }; +// } +// } +// } + +// function isGradientColor(c?: GaugeColor): c is string[] { +// return Array.isArray(c) && c.length >= 2; +// } + +// /** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ +// function resolveFill( +// defs: d3.Selection, +// id: string, +// color: GaugeColor | undefined, +// fallback: string +// ): string { +// if (!color) return fallback; +// if (!isGradientColor(color)) return color; + +// let grad = defs.select(`#${id}`); +// if (grad.empty()) { +// grad = defs.append("linearGradient").attr("id", id); +// } +// grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); +// grad.selectAll("stop").remove(); +// color.forEach((c, i) => +// grad +// .append("stop") +// .attr("offset", `${(i / (color.length - 1)) * 100}%`) +// .attr("stop-color", c) +// ); +// return `url(#${id})`; +// } + +// /** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ +// function getArcBounds(startDeg: number, endDeg: number) { +// const lo = Math.min(startDeg, endDeg); +// const hi = Math.max(startDeg, endDeg); +// const angles = [startDeg, endDeg]; +// for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); + +// let minX = Infinity, +// maxX = -Infinity, +// minY = Infinity, +// maxY = -Infinity; +// angles.forEach((deg) => { +// const a = deg * DEG2RAD; +// const x = Math.sin(a); +// const y = -Math.cos(a); +// minX = Math.min(minX, x); +// maxX = Math.max(maxX, x); +// minY = Math.min(minY, y); +// maxY = Math.max(maxY, y); +// }); +// return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; +// } + +// export function GaugeWidget({ +// node, +// variable, +// title, +// theme, +// className, +// style, +// width, +// height, +// minWidth = 160, +// maxWidth = 480, +// minHeight = 160, +// maxHeight = 480, +// aspectRatio, + +// variant = "progress", +// value: valueProp, +// min = 0, +// max = 100, +// size, +// responsive = true, + +// arc, +// track, +// fillMode = "progress", +// color, +// bars, + +// needle, +// labels, +// valueLabel, +// needleLabel, +// scale, +// ticks, +// segments, +// thresholds, +// animation, +// tooltip, + +// classNames = {}, +// onClick, +// onHover, +// onValueChange, +// }: GaugeWidgetProps) { +// const svgRef = useRef(null); +// const tooltipRef = useRef(null); +// const prevValueRef = useRef(min); + +// const [fetchedValue, setFetchedValue] = useState(null); +// const [hoverValue, setHoverValue] = useState(null); + +// // ---- Live data fetch (mirrors CardWidget) ---- +// useEffect(() => { +// if (!node) return; +// let mounted = true; + +// node +// .getLatestData(variable) +// .then((res: any) => { +// if (!mounted) return; +// if (res?.isSuccess && res?.isDataAvailable) { +// setFetchedValue(res.data.value); +// } +// }) +// .catch(() => { +// /* fall back to `value` prop / dummy data silently */ +// }); + +// return () => { +// mounted = false; +// }; +// }, [node, variable]); + +// const rawValue = fetchedValue ?? valueProp ?? min; +// const clampedValue = Math.min(max, Math.max(min, rawValue)); + +// useEffect(() => { +// onValueChange?.(clampedValue); +// }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps + +// // ---- Responsive sizing ---- +// const { ref: wrapperRef, size: dims } = useResizeObserver( +// responsive && size == null +// ); + +// // ---- Resolved config (defaults per variant) ---- +// const resolvedArc = { ...DEFAULT_ARC, ...arc }; + +// const resolvedTrack: Required = { +// show: track?.show ?? true, +// color: track?.color ?? "", +// }; + +// const needleShownByDefault = variant === "progress" || variant === "needle"; + +// const resolvedNeedle: Required> & { +// length: NonNullable; +// } = { +// show: needle?.show ?? needleShownByDefault, +// type: needle?.type ?? "rounded", +// length: needle?.length ?? "medium", +// width: needle?.width ?? 4, +// color: needle?.color ?? "", +// capRadius: needle?.capRadius ?? 6, +// animation: needle?.animation ?? true, +// }; + +// const resolvedLabels: Required = { +// show: labels?.show ?? true, +// position: labels?.position ?? "outside", +// }; + +// const resolvedValueLabel: Required< +// Omit +// > & { formatter?: (v: number) => string } = { +// show: valueLabel?.show ?? true, +// precision: valueLabel?.precision ?? 0, +// prefix: valueLabel?.prefix ?? "", +// suffix: valueLabel?.suffix ?? "", +// formatter: valueLabel?.formatter, +// }; + +// const resolvedNeedleLabel: Required< +// Omit +// > & { formatter?: (v: number) => string } = { +// show: needleLabel?.show ?? false, +// formatter: needleLabel?.formatter, +// }; + +// const resolvedTicks: Required = { +// show: ticks?.show ?? (variant === "needle" || variant === "segmented"), +// count: ticks?.count ?? 5, +// position: ticks?.position ?? "outside", +// length: ticks?.length ?? 6, +// labels: ticks?.labels ?? true, +// }; + +// const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; + +// const resolvedTooltip: Required = { +// show: tooltip?.show ?? true, +// }; + +// // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- +// const resolvedTheme: WidgetTheme = +// theme === "dark" +// ? gaugeDarkTheme +// : theme === "light" +// ? gaugeLightTheme +// : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; + +// const resolveSlot = useCallback( +// (slot: GaugeSlot) => +// twMerge( +// GAUGE_DEFAULT_CLASSES[slot], +// resolvedTheme.styles[slot], +// classNames[slot] +// ), +// [resolvedTheme, classNames] +// ); + +// const boxWidth = size ?? width ?? (dims.width || 240); + +// const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); + +// const bounds = useMemo( +// () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), +// [resolvedArc.startAngle, resolvedArc.endAngle] +// ); + +// const pad = 8; +// // Reserve room below the arc for value/needle-label/variable text so +// // the dome never gets crowded β€” bigger reserve when the value label is on. +// const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + +// // Ticks (and their number labels) draw *outside* the arc's own radius, +// // so the radius-fit math below must shrink the arc enough to leave +// // room for them β€” otherwise tick labels get clipped by the SVG +// // viewBox, which looked like "some ticks are hidden". +// const tickOverflow = +// resolvedTicks.show && resolvedTicks.position !== "inside" +// ? resolvedTicks.length + (resolvedTicks.labels ? 26 : 8) +// : 0; +// // Scale min/max labels also draw past the arc's radius at the two ends. +// const scaleLabelOverflow = +// resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) ? 24 : 0; +// const edgeOverflow = Math.max(tickOverflow, scaleLabelOverflow); + +// const availW = boxWidth - pad * 2 - edgeOverflow * 2; +// const availH = boxHeight * (1 - textReserve) - pad * 2 - edgeOverflow; + +// const outerRadius = +// resolvedArc.radius ?? +// Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); + +// const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); + +// // Center the arc's bounding box within the available width, anchor its top at `pad`. +// const cx = +// pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; +// const cy = pad - bounds.minY * outerRadius; + +// const angleScale = useMemo( +// () => +// d3 +// .scaleLinear() +// .domain([min, max]) +// .range([ +// resolvedArc.startAngle * DEG2RAD, +// resolvedArc.endAngle * DEG2RAD, +// ]) +// .clamp(true), +// [min, max, resolvedArc.startAngle, resolvedArc.endAngle] +// ); + +// // ---- D3 draw ---- +// useEffect(() => { +// if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; + +// const svg = d3.select(svgRef.current); +// const defs = svg.select("defs"); +// const root = svg.select("g.anedya-gauge-root"); +// root.attr("transform", `translate(${cx},${cy})`); + +// const ease = resolveEase(resolvedAnimation.easing); +// const arcGen = d3 +// .arc<{ startAngle: number; endAngle: number; r: number }>() +// .innerRadius((d) => d.r - thickness) +// .outerRadius((d) => d.r) +// .cornerRadius(resolvedArc.cornerRadius) +// .startAngle((d) => d.startAngle) +// .endAngle((d) => d.endAngle); + +// const startA = resolvedArc.startAngle * DEG2RAD; +// const endA = resolvedArc.endAngle * DEG2RAD; + +// // --- Track --- +// const trackSel = root.select( +// "path.anedya-gauge-track-path" +// ); +// if (resolvedTrack.show && variant !== "multiBar") { +// trackSel +// .attr( +// "d", +// arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! +// ) +// .attr("fill", resolvedTrack.color || "currentColor") +// .attr("opacity", 1); +// } else { +// trackSel.attr("opacity", 0); +// } + +// // --- Bar (progress / solid / segmented base) --- +// const barGroup = root.select("g.anedya-gauge-bar-group"); +// barGroup.selectAll("*").remove(); + +// if (variant === "multiBar" && bars?.length) { +// const maxBars = bars.slice(0, 10); +// maxBars.forEach((bar, i) => { +// const r = outerRadius - i * (thickness + resolvedArc.gap); +// if (resolvedTrack.show) { +// barGroup +// .append("path") +// .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) +// .attr( +// "class", +// twMerge("anedya-gauge-multibar-track", resolveSlot("track")) +// ) +// .attr("fill", resolvedTrack.color || "currentColor") +// .attr("stroke", "none"); +// } +// const valAngle = d3 +// .scaleLinear() +// .domain([min, max]) +// .range([startA, endA]) +// .clamp(true)(bar.value); + +// const barFill = resolveFill( +// defs, +// `anedya-gauge-bar-fill-${i}`, +// bar.color, +// "currentColor" +// ); + +// const path = barGroup +// .append("path") +// .attr("class", resolveSlot("bar")) +// .attr("fill", barFill) +// .attr("stroke", "none"); +// path +// .datum({ startAngle: startA, endAngle: startA, r }) +// .attr("d", arcGen as any) +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("d", function (d: any) { +// const i2 = d3.interpolate(d.endAngle, valAngle); +// return (t) => { +// d.endAngle = i2(t); +// return arcGen(d)!; +// }; +// }); +// }); +// } else if (segments?.length) { +// const scaleAngle = d3 +// .scaleLinear() +// .domain([min, max]) +// .range([startA, endA]) +// .clamp(true); +// // Half the configured gap, converted from px to radians at this radius, +// // so adjoining segments get visible separation like distinct blocks. +// const gapRad = resolvedArc.gap / 2 / outerRadius || 0; + +// const segArcGen = d3 +// .arc<{ startAngle: number; endAngle: number; r: number }>() +// .innerRadius((d) => d.r - thickness) +// .outerRadius((d) => d.r) +// .cornerRadius(resolvedArc.cornerRadius || thickness / 4) +// .startAngle((d) => d.startAngle) +// .endAngle((d) => d.endAngle); + +// segments.forEach((seg, idx) => { +// const segStart = scaleAngle(seg.from) + gapRad; +// const segEnd = scaleAngle(seg.to) - gapRad; +// if (segEnd <= segStart) return; + +// const fill = resolveFill( +// defs, +// `anedya-gauge-segment-fill-${idx}`, +// seg.color, +// "currentColor" +// ); +// barGroup +// .append("path") +// .attr("class", resolveSlot("segment")) +// .attr("fill", fill) +// .attr("stroke", "none") +// .attr( +// "d", +// segArcGen({ +// startAngle: segStart, +// endAngle: segEnd, +// r: outerRadius, +// })! +// ); +// }); +// } else { +// const valueAngle = angleScale(clampedValue); +// const barColorRaw: GaugeColor | undefined = +// color ?? +// (thresholds?.length +// ? [...thresholds] +// .sort((a, b) => a.value - b.value) +// .reduce( +// (acc, th) => (clampedValue >= th.value ? th.color : acc), +// thresholds[0].color +// ) +// : undefined); + +// const barFill = resolveFill( +// defs, +// "anedya-gauge-bar-fill", +// barColorRaw, +// "currentColor" +// ); + +// const path = barGroup +// .append("path") +// .attr("class", resolveSlot("bar")) +// .attr("fill", barFill) +// .attr("stroke", "none"); + +// const from = fillMode === "solid" ? startA : startA; +// const to = fillMode === "solid" ? endA : valueAngle; + +// path +// .datum({ +// startAngle: startA, +// endAngle: +// prevValueRef.current != null +// ? angleScale(prevValueRef.current) +// : startA, +// r: outerRadius, +// }) +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("d", function (d: any) { +// const i2 = d3.interpolate(d.endAngle, to); +// return (t) => { +// d.endAngle = i2(t); +// return arcGen({ +// startAngle: from, +// endAngle: d.endAngle, +// r: outerRadius, +// })!; +// }; +// }); +// } + +// // --- Ticks --- +// const tickGroup = root.select("g.anedya-gauge-ticks"); +// tickGroup.selectAll("*").remove(); +// if (resolvedTicks.show) { +// const count = Math.max(2, resolvedTicks.count); +// const tickR = +// resolvedTicks.position === "inside" +// ? outerRadius - thickness +// : resolvedTicks.position === "cross" +// ? outerRadius - thickness / 2 +// : outerRadius + 4; +// d3.range(count).forEach((i) => { +// const t = i / (count - 1); +// const tv = min + t * (max - min); +// const a = angleScale(tv); +// const x1 = Math.sin(a) * tickR; +// const y1 = -Math.cos(a) * tickR; +// const x2 = +// Math.sin(a) * +// (tickR + +// (resolvedTicks.position === "inside" +// ? -resolvedTicks.length +// : resolvedTicks.length)); +// const y2 = +// -Math.cos(a) * +// (tickR + +// (resolvedTicks.position === "inside" +// ? -resolvedTicks.length +// : resolvedTicks.length)); +// tickGroup +// .append("line") +// .attr("class", resolveSlot("tick")) +// .attr("stroke", "currentColor") +// .attr("x1", x1) +// .attr("y1", y1) +// .attr("x2", x2) +// .attr("y2", y2); + +// if (resolvedTicks.labels) { +// const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); +// const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); +// tickGroup +// .append("text") +// .attr("class", resolveSlot("tickLabel")) +// .attr("x", lx) +// .attr("y", ly) +// .attr("text-anchor", "middle") +// .attr("dominant-baseline", "middle") +// .text(String(Math.round(tv))); +// } +// }); +// } +// // --- Scale min/max labels (drawn at the arc's real start/end points, +// // not floated at the container's edges) --- +// const scaleLabelGroup = root.select( +// "g.anedya-gauge-scale-labels" +// ); +// scaleLabelGroup.selectAll("*").remove(); +// if (resolvedLabels.show && (scale?.minLabel || scale?.maxLabel)) { +// const labelR = +// outerRadius + +// (resolvedTicks.show ? resolvedTicks.length + 16 : 12); + +// const drawScaleLabel = (angle: number, text: string) => { +// const x = Math.sin(angle) * labelR; +// const y = -Math.cos(angle) * labelR; +// // Anchor away from the point so the label doesn't overlap the arc: +// // labels on the left side end at x, labels on the right start at x. +// const anchor = x < -2 ? "end" : x > 2 ? "start" : "middle"; +// scaleLabelGroup +// .append("text") +// .attr("class", resolveSlot("scaleLabel")) +// .attr("x", x) +// .attr("y", y) +// .attr("text-anchor", anchor) +// .attr("dominant-baseline", "middle") +// .text(text); +// }; + +// if (scale?.minLabel) drawScaleLabel(startA, scale.minLabel); +// if (scale?.maxLabel) drawScaleLabel(endA, scale.maxLabel); +// } + +// // --- Needle --- +// const needleGroup = root.select("g.anedya-gauge-needle"); +// if (resolvedNeedle.show && variant !== "multiBar") { +// const len = needlePixelLength(resolvedNeedle.length, outerRadius); +// const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); + +// needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); +// const needleEl = needleGroup.insert( +// shape.tag as any, +// "circle.anedya-gauge-needle-cap" +// ); +// needleEl +// .attr("class", resolveSlot("needle")) +// .attr("fill", resolvedNeedle.color || "currentColor") +// .attr("stroke", resolvedNeedle.color || "currentColor"); +// Object.entries(shape.attrs).forEach(([k, v]) => +// needleEl.attr( +// k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), +// v as any +// ) +// ); + +// let cap = needleGroup.select( +// "circle.anedya-gauge-needle-cap" +// ); +// if (cap.empty()) { +// cap = needleGroup +// .append("circle") +// .attr( +// "class", +// twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) +// ); +// } +// cap +// .attr("r", resolvedNeedle.capRadius) +// .attr("fill", resolvedNeedle.color || "currentColor"); + +// const targetDeg = angleScale(clampedValue) / DEG2RAD; +// if (resolvedNeedle.animation) { +// needleGroup +// .transition() +// .duration(resolvedAnimation.duration) +// .ease(ease) +// .attrTween("transform", function () { +// const current = needleGroup.attr("data-angle") +// ? +needleGroup.attr("data-angle")! +// : startA / DEG2RAD; +// const interp = d3.interpolate(current, targetDeg); +// return (t) => { +// const a = interp(t); +// needleGroup.attr("data-angle", String(a)); +// return `rotate(${a})`; +// }; +// }); +// } else { +// needleGroup +// .attr("transform", `rotate(${targetDeg})`) +// .attr("data-angle", String(targetDeg)); +// } +// needleGroup.attr("opacity", 1); +// } else { +// needleGroup.attr("opacity", 0); +// } + +// prevValueRef.current = clampedValue; +// }, [ +// boxWidth, +// boxHeight, +// cx, +// cy, +// outerRadius, +// thickness, +// variant, +// clampedValue, +// min, +// max, +// fillMode, +// color, +// JSON.stringify(bars), +// JSON.stringify(segments), +// JSON.stringify(thresholds), +// resolvedTrack.show, +// resolvedTrack.color, +// resolvedNeedle.show, +// resolvedNeedle.type, +// resolvedNeedle.length, +// resolvedNeedle.width, +// resolvedNeedle.color, +// resolvedNeedle.capRadius, +// resolvedNeedle.animation, +// resolvedTicks.show, +// resolvedTicks.count, +// resolvedTicks.position, +// resolvedTicks.length, +// resolvedTicks.labels, +// resolvedAnimation.duration, +// resolvedAnimation.easing, +// resolveSlot, +// resolvedLabels.show, +// scale?.minLabel, +// scale?.maxLabel, +// ]); + +// // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- +// const handlePointerMove = useCallback( +// (e: React.PointerEvent) => { +// if (!resolvedTooltip.show && !onHover) return; +// const rect = svgRef.current!.getBoundingClientRect(); +// const x = e.clientX - rect.left - cx; +// const y = e.clientY - rect.top - cy; +// const dist = Math.hypot(x, y); +// if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { +// setHoverValue(null); +// onHover?.(null); +// return; +// } +// let a = Math.atan2(x, -y); +// const hv = angleScale.invert(a); +// const clamped = Math.min(max, Math.max(min, hv)); +// setHoverValue(clamped); +// onHover?.(clamped); +// if (tooltipRef.current) { +// tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; +// tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; +// } +// }, +// [ +// cx, +// cy, +// outerRadius, +// thickness, +// angleScale, +// min, +// max, +// onHover, +// resolvedTooltip.show, +// ] +// ); + +// const handlePointerLeave = useCallback(() => { +// setHoverValue(null); +// onHover?.(null); +// }, [onHover]); + +// const handleClick = useCallback( +// () => onClick?.(clampedValue), +// [onClick, clampedValue] +// ); + +// const formattedValue = resolvedValueLabel.formatter +// ? resolvedValueLabel.formatter(clampedValue) +// : `${resolvedValueLabel.prefix}${clampedValue.toFixed( +// resolvedValueLabel.precision +// )}${resolvedValueLabel.suffix}`; + +// const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); + +// return ( +//
+// {title && {title}} + +// +// +// +// +// +// +// +// +// +// +// +// + +// {/* {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( +//
+// {scale?.minLabel} +// {scale?.maxLabel} +//
+// )} */} + +// {resolvedValueLabel.show && ( +// {formattedValue} +// )} + +// {resolvedNeedleLabel.show && needleLabelText && ( +// {needleLabelText} +// )} + +// {variable && {variable}} + +// {resolvedTooltip.show && hoverValue != null && ( +//
+// {hoverValue.toFixed(resolvedValueLabel.precision)} +//
+// )} +//
+// ); +// } diff --git a/application-examples/my-app/src/assets/hero.png b/application-examples/my-app/src/assets/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..cc51a3d20ad4bc961b596a6adfd686685cd84bb0 GIT binary patch literal 44919 zcma%i^5TDbT`tlgo2c`(n!ND-Q6MGAYIbZ-QCh5-QC^YozK_ne*b_MKK#O- zIWy zd$aJVZ?rl%;eiC7d#Sl-cWLv9rA0(UOX(@I3k&yyL+3GaQ4xpb1EGC|i|{byaTI># zBO=0pyZu5XO!hzGNPch4cx%6XJAJpDa<+98BOcYNo1=XER1sv!UW z^>ZDMp%FSmVnt)n^EIR+Nth`vRO^_=UF3EWv75ym{S;#2F8MPot@-y$>ioj!)a1bE zijXPQY;U`qNwl9|wl{W>{FhMSb<>m4{;8Udp4psl)NwFRo(W-T)Y6-qDf=L#U?g<@ zV+T|3+RuE~!E&nodKrkfPcOpJ)&1|p`Tbtd12@MSE8DjWkD|9M>GZsHLf>TTbLx)B z#5K5l%gS7s(yWk?Lj{Nvm`Z-s8xb-Xr`5-xRr%w8v>!oSz{dN*MmxbscQl#Z40qSd z!PQXs-utLEF&$@S#__Lo*pOhG{l(%jyCh-0ME8owiT>U~r&q@MaDRePL(aZAAff9= zBd@*7RZxmiqK^nZH7`bTjIEQw#Y=V6(h{$>7ZIf=7S0;$8~4NXLd4T;Ai~C8&3k-; zYEtJWq6x$#5rrCJ%zspgO z((R)&>BIkkr^qQSEZljO*B+ZDvTeBKJ9N%8Ej=U+62GI)dc|ZMEM66~W12v&QFAIS zoDs`J`wjsl?WdE(NTnjCO!^yB>{yU-2UPT`&FOyVQVmxy#un2Po>GiPPfzd0M^d_i z+Kr}dPhIfsDLd~jOiJ(sHTN;2u)@MaX&0AdXR;BAwr_;1sR;)MM+&{XTzNnKWH@0a zoy9ApaUt=>jjHICu3W42)5;nzHS!M3?aOvZfv-sIc%wc9#l0uHFc}aS4JSrIDOQ?4ri_bS?pjH{U{6qr+6m z--%u=5oc&PxE==-I$~$5gw}yiu_y_o?|ag2+rAgSg%G)}EU}r%*A|v|pjbE`lxJpU zy0{?;(US(i-TiKq6s_(KTYy|YVi&!plMT)EJ4wMU{C7Y;!Xow1nJ+X@ks@r0v25R; z*o$8AP*G*f3$UlYR~18PxKyPj9vU#v)4#GgEx4*?KOhlh>0%3M$-LN7&b*0fXgm$k zH78>bObkx^3_K+RY;G+Usy6L}p9iT!hlnJCmR=;=JL1TdtB#vL!RTJ1TABQx8Ux0w zl^{Jkf(hU>-jr59iK_v-PkV!WwG!LvW<@{3{IbbSiWBrX@S8^`8JFRrc+(AqsUIvm zCTstACtCZ~qy-5^Gr@_z#X!N1*1vH=7@8oL4AEOxWl^YW&LW|1$1J?gG061vk1epe zRI_*s(lrX?-2#tCt_`)p?{zZC+)onl60CU~%4!vPA}h0+fB9ucNkTQ3u29((9Wq=> z^JUm|{_2-=?dMKu&9)#x{lgPOCM`U1^tXDbmZ%I$0fw7|Y-@3Tyj1LGfk$lvzYC85 z=R()QEER%Dz=mTMZ=7E?K74&?)4b~-uj34rKwb~7vU(48%+1xYc^VYn| zncI4NL8xEnmi>eM9EK&~si%*s|BX@zKIUU?cAWA5pdc`xEZIF1Ce=Wcg3#AP?N~p# zD7mfb{oR=ZPE^jgwD3G< z#8h1K&u&zKD4q*Pxt0ta#d}bm;QqZ!hFift22a~7c529SkmFQyN-*H zzQck2cL5iH2@d@Lhq4$~_!wMWL6(&mNq=7HhT}YYI$pVVZeQr>)4>qObE$PPNZ2!0 z&7?y_upwfiefj8-`B$ju)}QKTz*Zs<$Lb?XHBo(jyU(405&`EL({mgxA$Ov49U|rN z2@(l@n`1vzG(v=!u4AZ*0s}~H4{VgcNOJ1rB?Kg!=)mGHKWeC|MHb>aiQ4Qd+gq7|??WH7;?J+kYL8z# z@juTBhW#n3rN))N7T1~)qr~Es;2rln6_U>_Ejxj(E5%Cpoc^vfw64mua!ADSZ8i|+ zB}g?u(dtvesTegnG!9K33T)4eq>)>ZFp?L>R8Qp#(J=bxz2mscD;ZNoJB@ZUqPpI>o7VgScniW4c()#;@;-9PfR`b(r+#4c; z;1-)`!?b}4A3v^zVtGa(a;O%bzu(ZG;(l4+W^vU|a&n*xV0kU$uFQ!5!aWy)^q4^r zn!-6hfj79_B#>GGNvQiKMD?xyW>F&GS>3y?Ric*xp4cz3FH3Gd1z|e+Vuug7*Ya48 zL~K*l5zo1XRuWm%S~GzE4LQyuRsH1&L`Gz-%>!ZTYn9K_Ttz+Pa@9hKob^)gmLVN` zKJz}C50X$$>G1Q_p;%C}B?<9h`60%vwalt2*Ymd44dGF(oOa2mJQuPQmE~Yurn0UC z6(+5$posAd@e$nvJQFL^C~E0E4IH`B68)j#L_u|Ex5mNE8a8{>gAGcIFVS|K?g77# zE@R|9nR>Rw3(5}{d~HnPpooZ*XZC$5FYt20 z3Ydvy9t)XHw8qFCd;mt8r$e?RQ%MiUF@}!oDGG#E6xxV z=z>11f!msSqbAZYnSvt}&J+QXZCU5b`0!gi_R}Z@Qq2d2Mwc z%9aWfp&x2UGbLDvtjGb*p>4O(#}UE+QhYmf0&Vc_Ay<~3V0zym%`Lk}-3MOz<%)%#Pl z<=OjGrvuBq318+CJ-{30QA1-O@<-O!-zFNM^&wp}iWGG$B&eIYtF)Rs4;5FK=>Aa9 zyTJdUgpK$di~MI|ZC=Vkd^V6T5h^z))sl~Dq7~stg?&l_LW6N1>0nX=aS46Ks+vj7 zr#P2~h=M-LLX2!W_k&dv^Tm2}o9vK&uKMDMmPkEcj7~C78vw2XJx^s8uo(Lw>9ET2 zzXG^MDxZzwh4y=Hs@h^Y2$ntYP+GSm>#cM9ZiUR^>tiFtIol3wi8=y~L2f@Bun;{B zr@yZMir9Ur@yw@7ni+Jd*Oc9hFx zK$M%P9+XKj>`spPB?k6^h1pok(_k*E$fr(SnXlXEnE{ODRWuWqB2u+8*2z?-wl+WC zntSCtFwpr0nF!avN+7`^Pt@XDvec7%ipuHYXg%5TXDAXv;U-33A(vzDB8V%0%j-R@ zk!2mox%%pJ<_M$o0lf*YButy@IP%9Zz=UDDlr|NuSNW*bYB{&18Xj|$eVP~(lx>y3 zgjJh3l1)5_uw6CTgk`ABQVoCHT$nbFS*edKLAbhRxLyzMI-{#6H!q_O@+mM7#~@Kw zWFDq#m<+NGVr`grM*Mh=Dq@8Tzl-$WKFWsWruYa^v`B30wDORai8q&__SDBzc?K#o z^UN`hN&IN;bep+mS1Z}i#zurS+Vl`B&+6`B#XK@l^8+&2+e@&zII(kdzid}Lm^AE5 zqjZ+3N*0O?1%{glymHcUP?g3vB#mH9MA)__>pUakjX+4jPuRS$9mmbImM8^= zOGMzKSY0_htZs;&-)|di4DJjSjVQ}hf2vq`u?G4@2@M(y#8xp{#1&$)ZW$rlUwG%{ z-S3I$D5~^(7stnQ#qh(0D6TnSA5R2*0u@x*22u1y%V5wYfW$b@)H*9X9{5!1Gw0`$ z4^fR@T%cw74(zCoPNP98@iS+WaFoE>g!a7#s-iwfRHKJSou%<97*I%619(655MjTr z6;k$p>T1-|cb9V=`;0i>gjBf%t=3jn_oC874-1o3(J|G-g$c?a=wn!m?U?CAd4WKW zm>=k4ApUHFtra|}Wl_G|#Y@n(Qv*q-frfU@rg{K1dLr%5(jA(Als7lSt8bue+zbab zVF0VKb`8x4k`2s^D1=P<^mk&LXhA!1jsr46^sGC@bsZfT)hZq4gnT+I+aHp`_XRE{ zDgx9ExOOSGF^DuVB_iQ8s$S{7agA7rKLtYG0nVl0q1kdJPQ3g#tw9qL?gP!_e~V$R z7B*H7J0{kp*t0|SM#+|$l6`>>9*GXki2@B!1?#&`s}t$D9D05bdTLaq__DzJ3hhhx z4>Z*xjuhGkL>lPDr8KhXi~8N*3~eqgebLTG`3g)&9`ESMo4O`ywJ{RymGvLXG}!Y?yAZ!5^Y19ukC`n~3GM7)2v! zx|C7WvVV`|+~>K~FRJPdp3VTPY##;_7#_^stFuo>5ewhPn5=@ApsXs_<27I&gPv>g~?s5SHzci&*$xeFVsI6?MsNJwojSpg9-+xbDwNanO9CUPbs06^E~@ zW3}{)@boKx;MgISD4?gb;X2~Nzv6Vu z_d;=oiM*wq!ou(NN8Zrg1ZYYlE==ylKlarfHe9u21xL{BI8t!pRC1^0=DGRrV0_Q@ zC#L85xcROt(T$6-@Y|KI-@7cgFD>WF?-)WG5jRleK;pn&=Rb9nZ+_@Mx-Fk~VSb{E zq@Ay=ub)@s&Mz*$+FSlG0WrrMKZI+3YuZ5k`RZGGO+r;}6mJy$DM;>AadvNZ=5yf|1r(je z0NIXNIS||Cv*MHEs{?>y+_cZmakNb+;cq-QqDcP%tMf{NmoE%a zN}Y33Vukiwxzm0dhmNsZQ>TsfYfZ-XZJv?ZTQ(=j1nt6FMd#;_K1oqQ{yq$GC6%)U zZU3B>;dh0p{DE?0kaj|iKj8?vvgC|-pv7<_WZBV7+B?`x+~3_las0^52<3d}UOOFD z7O7yf($skvy4y{NCq)B!Z=x|~NnJN+V(IV6LPL~?ORfvDDj*}q67_9}bTd~ci zlKmqOV)pG2tgWwY4Xr65@I8rddMwBV71bVAeGxT?v8-f6l9tsu9MFYr4r+BQr%mT; zO=G1)NW}SP4_kI0273Ew)qtwOwo=X-`1?bJ^>I^-9FXhSX17W>;{G^F+<9U(<%-*JPc!x>jH zSpfzK?Tx3%`#8Qlql2)Lf)TAiKHBQ5IOieg6~2NY7g@9IFI!7$DETtUG^srTsi2YS zc$`cq59-bK0{Yv})|#O4%XrxCkS29A6q~iTWNRlF;SlDMr$~v5hgerQQg_UB>M>2% zI6J+NtM*`(N7ghI_emz^lYyF_O8LW&&6oX-gU1h39L7r@8tpHA@>FGx*W=fR6E@q@ zg{!zJeVuJaQCuA=1@IE7|3##J$1oumJ5vky^UJEjKU#$)KuHS7B;vs(wJ%$?>4zlr z<=b*ca@HsJ!Osy3xBOqrn__D7pqhw2^7;n0$R~Z;twx??hrssk#C1cMtRHfFzhTG1 zE{;!Tmiq;ZD9#2W4(M?+!*~v>l$%5;__SINKTNAEIBf46X8185dhp4TD9_K#gp?em zl9d>E%I2x(q#pB8rt!89i!Mi7sMMmaZ?N?eM2!JHoQ{QdAoSm@`@TtaEkw{)WuZe^ zzrVO3sL=ewi4YYv1t!gfQ_Xo()Is9PQtqh!#?v&Mscaiz6wb$F>GjZE1xw7d5)*24 zu~!(MAawsNH*G-kU-c=3l(?|JJl0^q#LV(WKmSHC=#5YKstmI(V=6c4>73kKDwk3F zD!sjK#(*WYb8j>uP??1gq4SEU63;>Pk_#yOYu7(GAy4!ABPQY-WoeY1I=l2&k9RM( z;&F-Ki}KoHAb;HXNP-^_3u`-L$+~dmP7LmypyE23q+IsyIAyGbu{1T^)Y7+m(;oN@;N26N#9X<& zwqI@>wi=7v)<%`#h|WWx1pPuT%3Hx zTmHj4u@(m6TMc`y;_9#P8As?uJeu-!|Lgzd>}uWMUo5{kA<)1ndxs@UZR32fT6pJHGaO!4QH(eAa5+t zS1N59EQ1r6i z<(E$QmAL~w+VkGpLI9*Hnm0tLT@_hjW9JWQXev%DVG3YZJ@}x78{*jc{asC?1L_)h zF^DC#%H`1`O_VrpaQ}@~&1zbs5~&ja^i#ZVXwP!}j8mnEV@;<{Ahw)4%S3LKNFJ3i zaiK4p7j50(Gg`7o7JU5p$cw9Ok3@$*lZ@g;nFZi|2gmE)4`U4Rnm2m{vKk-zbX%kA zCoK32`kIhZtyUTzRW&2mT0PG|s|zU{4QPllcC91scP>F97ZXap<9Bv#F$2P|qk;b&2$rxv~0fH76P8hs?SUZLs6n%pW)x z{94NZ^zuBrMOvmx1jBKr7I^C(e7yj;&kgD*7xRHBhV0n=;gNznW(J%ArEdQ3v2RnW zr(kstOqa&TJ`*F&kJM}we0``YRAQ>!`T?;}wzZgRk(fa^)#2*9%Z+psyrobKU%nac znGGN&)Npn`s=}e$R4yL6IsRDDSF=Ps)Z;1?NH}K#C*jVV4dx0@(DMhJqOL*I6)&L4 z9cLFcW!bbaiw~-ib4#2tjht6tOE}{zD6zU{xlC2$ zI>jGRD=rdrA25&Qq4jqQAhS4A^TEeuR}+ZLmIn&KRN3!3YkB-ej*-b9-c-AE)S%N> zf?x6evrm$2MOQ(b0-<^gvSC_6oBe@p+i`Ajxy1G91_dbm9z>* z`v6e3>~L1a-C*c2`$0^HXjr4(?IN{jFy+;}uvyb!LNh16HAJ)d@63e8GRMmWrMZ&F zv_aLU&4#ktx$@=QM^zZSdGAFn^&JpWIEc06k(WFQd*!&PpmY;wf3>)TvXQM+vqd#z zyU8VT;5@(~T!27u_1N3Z<{-f&SNd-M>^C*BK>cKP5&U7*KXmq@FP2FiN4aT+-1iF~ zfRiPbO{*ky%`uehvD+s~XnH7V{jvXcN8((ts-<3M-#N&I$MX3xlZ!UGg+fiN+}`r5 zkj3AjM%Sj6BRHE5?Q@(GmaEXx+0)r!TPtcgyrsy<^`_Wc*hwyr-;OCdQ4#vF=h5Xj!r_#p6O*Q* z)GM*S@GP^XHnavtL<^TD>&W%F)LS4nt}T73^w2{aE8S?2vByR~WOdM+N!yff<@?z8 zI#ww-Zu3B+Dw2VJIAV7nOX9!ujfO>l`;d|vXtw#0QXN#ak`$I0n8kN5(2;87J-CD? zHmL*sL>eCfe*GTXwvDI2D~K%nI37JKu}-!Po8ExO7L8{#pw*RuB`6KEDkQxqNdG4R zbz*yTL(6Iv2z+#WI#BgSE1!LJckdfI7H#~xxtSQ;JHtJbofI^}g8L7|Kn}2;V?6dd zK9bChE}t-w#v@|YYe!RB4PsH{@hW+RWHlR3f&YL23-N7 zB={^p7mTZ^ud}HaFV%4UvxHK!)luf%KBVaoi+}5rSQwa@bCw;vYHCGARWld==<7kL z=59v02kEeG3Rm_z)Zc3=MXmaA)I9-9T+O+St{6L3)`@2_41VCAA&8E3bj5sZx5x4s zmtI{uQpw=7HHzdjnUy|za5p(fC=*%NXWhuB(Dh_u6(6Y_e%!8tO&OI$^_@sEYZMc) z<_`+vf$U0(c!m5aMnvIZvM^uI5SEj)Z(;;xrCT_CmpZM4!RQ9UsISG;<-MiaiPA(v1+;q7waq z#DaO&yeXX-esRlYcP9QBezojM(;1VYYslzFHa5kqnhTql9tB)(1PR83ymJM)zr}u2 zA!bL-PF~HWs6_&|a2T`59w8gMCgzI0ZUSUfQfl;Ojkd&KMV<)NhcnfxuOH2mUXuwQ zAM*!OvW!{`MXjm7TIXfL-k+n%0dP~x1% zi$3~@96_CUQxT;Gzf^B~3kR0u=7eg2I4Fgw5M>k5m~x;XrP_^xUNLYFvz1}cRTX7r z0lHVaPz&tCq!B@(_+nwtq0RK$#IV+@P;sE{>RX8Bn-rrhrkj}46K*PBvhLdC@?i7h zJjx#Hk>f+3F<_Y0nGofcP^IE@)+(L~Q4*1fl-B_6231_D^dqI(^dhIc= z=LA*Dx+nYb(z7F472oY=W@o*6`ujtJZ|o#z!EAVr%)^Fux|HNxTtvhvDsp6UwTFwJ zM*F1zvWTTAmTD7v5DPy;dkkH$be+d!3z!mh9?~B zP;G9Vwc=}F40A(Sds~L)9PeFHO$%36su`>ADF4lttX|1!{}kJEkmfex*_yNVfSVdD*&UI|G|lX40rxwlAPgKpuk`23wH2sCfRuKK%fnp1R#=<@<9%+; zML4y^o|%u9_V0m5cLefgy9n<{uobfvYeu+aZKo0Ktc|gWw&pasMBNnfI2UHbKn{9O z)8)imqR}+@&r{T;xui0wrvTi{YW)CT-RWebe0G8{202Acf|Llgnqf=$=%XtXfK4Qv z=zT1j1nI9*CySKsm0?}}<#3SfXM2MsnAkgZs>SG?0o-+s-LK%L80d)#K;3u!6;8=5 zX@g4Fm=G<8m!gGW=R{0399feKC9Xe6!If(%Vf-@0mQ7tBX0NzqmY|9qPu^277yohID3?W6U;XA5NfW2T%outqW~PhQ+n&nro#DcM$Z$THW`N zvNBz|DwU7qm-tFK?Q`5dA&PTB@?7}m0eDq==POEw^{A`Fa?qK z&48UqJjKg|to+>?O{Xf0(K=JOzIa?8#vDp}6Rf^uG9;_RQ>Sv54OQdMjViE9g742S zMhS8Ye+*}NihDGfGuOzbNvx`CgC7KR%vHu{O-ehz$6LT4Mk3SiWVM?^5C{rNs<(ci zqw`nSS8I-1*=qA%mSmm%)UgQ`dsW)FynP!Cpz`|ATE_}k?|*Q37_<7=60FiHwB(_h zw5+MMx={v+RgSy*%jLa^{Rki@+7`oxIZt}@^zY`)n@lMhgAPv!!2u;Sa^;2L@?^x z%A-Mrjx%teimuzTAPSO;F~lr&gy>_G4IY{^P*NEOF|%r&ntw4|Ix}Z6Za4>|Vq}%A z6pcxIPQ@tDsnqjX?bEekhr8)RQoOi)#Gg%k8s-M;;psx6&rT16qf|d(x zQm|i=dq2&*4+`a7Tfs#LSH|);MEHt+!b{0d7;B0PK<1QGH_ynoq!E*2hGkz#6O9hV z?$@wob1i#9kmr+^>ORB=Br!O}1{@=Or zo%h~IPq;QRxJrZG=B=N=LCa3_ths#xboN?(E~BHD0#-A0HRWBd% zQcIeW%y@>zZ8l81ks#C7e+hpvP3-w#+7K8!Z#+falSF*kz#{e>Br}RGNxX7AU1lVi zBM!bs|1pEQkrg!e8V!3s{|$r6OO-b5{0em=IHTj>B%>xTM{2fQAz|zH#Py4>+?xni_0O!81gn!QL~C|A^iO>kV^4a_%tZvJM}($5)k4nG z1`n!DqAq7NrQbVbxd2VW=*}I~?A_RaioH~%?eBYLjJ5@FW1Pu+UAm(%H!%U>%pk7} zejlDzFG%i?NWK}?hzUWsKEW}sW!hRv85emvYXb>bj9PjkEJUSs#y-}~vu{`L=EN&3c~hF@`6?yd zt*{wD)SEe5tJzqXKE$Yy+1IchWywJgfw_Q4!wv!!5v&6E{)Mf7)=|Ty$5R8b@U^UT zH*#GGHSYPR@bGZ$75&;Bj!Dh8Z%`1MNltRwF(-lxD(>)-*7(HhmG5nQ+i+Z`;k`|g z%h9)2??XolklwMj)H3$J>HaS9heUSwj9nb|SnvxxR~23MWzjJ&wWNu0GHR|_`D@uU zJcWrzlRcU6ndDlgFI8Lbxu<+@@QxstO@yNH$yd+_nh{q=e4eP<==cK*H3z8Y(t_9COqt4~v_Qlm%pPjo%wZFKfn|@@9(-C_ zTK~A)tQ3f~*E*=hg0)-;lGt;ScvIjOMibwZ4x zJ_UAlwx$oR%6XV>upP2|637WYo24&Q}Y_fL*yf-Q)J=sU0Ln?t+}=J zO{6MCeh7$_?fo>?^zii23s=e9C&jWN+3Wk&N8il?$Rn1TVg8b_3$+-c4t1EpM3jNP1tx-~ZtZSw|kM3YHhY<3yn%Vn1xhDJu% z4Dv4H$I&nplNH^mY?|6wy=hopGrWsK{z&zWzg~2L(?_BXd*1qJV>321H#9~{E*{+K z!e9TFLZas6aujoB{o2~V*B17dvd{&Iqsk3=Epw1yoDK19=8B`6=j}^sM*D%B$mSlQ zX#nr4DX~ji#!=Nj_)ias_^{Y(lA?qcE`a>{=4^TOc?#56oiVbq2ANi8i&=TNn?&pk zt`VtbWh*T;WGoa9?%8a=={cj52ay?-Yi9r)62hP4b&xzbC(HecT>GQPlc<;0Z%*7x zZodr#pCg`OB3`dw!hrntXAoJmo=QMs$@kx$r(LhAPd=epl?(E@ zTyv?TwckxHOeIZy3=>WJv}?OuzDp~badvrF4_ zZAYU~d}%i=v{4M&=+*K|6X*V2+1Qvjc2Ko9YD}ENS~}lpu>xTCv^#n6e-9qt zhV_&E$RMR>%`RQ@$54%E!G$j!61RAW5b~GSPP)}#v)oupgLY4;dEuZK@1+Gg;XV}I$rIL*jyWr z%#b+Fa2-|41c5tm(GN?a8dVl1zFisqiPky)WPO?`%oSsK(Hf&IDaL(r`%S z-2Wn#BoRnHfqGV*!s*;zG-l;5+rkmw$u*-sA!lNdlNI=^8=bE^h^& zEODXG-PWduHouXLwjF4F!(35IXa!Q$a@o0)hwQe^4f(f-JAX*4-Cow;VDb*TZdS@H zqUd9T*+%su%e6L7M5t%M=UJ7V9HyWKQT0MWs3COo66`!uFnY3gmQjYiy2x8XhO@)> z$~WPw(}UW1aF~-s=CIaPH+8kG4exyi}ai$+h{shB*3W0rRF7=mD$#s zvR#Q@SDXD3D^=`Ph`BRQ^{vl_$cFGe&)d~zCy%|q@PdImLSty)@pAQ1>&enPc=}Hc zxK|095i`i|VQrKL0815&JK&dK9DdZJTv=}cxe}!(rRTVQA zz>Br`kSb^ePLUvOWki3xxKlM4deNqbyEV}je3vb|B;s5&FGql9?_#CDoYdH0y-F&x zmmEfNh6h@>F{QJ{ho4NR2lD=9hGNH2oIC_rb$IML zpQS^1(_7Yop5+Vhy%+YHF|E`%=bc9rjv2?=;WM~G<|FyL6?u#%TieI6z;E_?35N=+ z0Ixo25mhW*iKUS!M5jj`B4Aoh4{hmH(BZwuOSArZaffRMr0bkL=(zyx)q{3nGIFCt zP?|CQYOzYk5rJl?01bIJjV$ahRJVSWd3!3Z>FXU+^up2{FBnzM>P|-;XGsVkL5`RF z^7=C zeC2+{=kIBc)0DD5`G_YoUabnci0OMA>;XphacRZ#+lS*D8?ARGW7fDCOLMwkx#)by zx#YDL*_I7FjrWyjTBGud;0GL)qpsT(*rB1J-_=`Uw&ydA;1-mYlcj^y@4#eC#Oae{ zJMzbmnKyLiYBU&+6!x)+AHU8|r(4I|5gXO|yvLXkB8XQ!H zX2baRkI_{jpLFvC2dRbFcD)-@6RwWk6)$7O2aHGPQ4w5Ljz{X^ANl66!{l)US^OWr z7AZob!By7dm7H-cRkSe7adHaySI*vu#vJk0AzD%0Oj~;1NL0@B4>hMui3vafOxJH( z4|j*!N321k^8ELv`Q|voWIy=68f3oF19ight;SN>tLXSx=j7MN<#sD^G zXN=O6OXa?}ym}R~{&5qmA3br7O-gH%p>*6pf0>seX8#r;TT_si#b~RwReA-by-m5@KaM)U^CF;34yDGKb(cEIZa6%3o05E4cb7* z+;9{Ba~%6OZ?QP*qY4Lw{;`lW{Fw2)eDG(3ZA~DV=!e=H;w!?-D#OdFS1(gG zyzFg7o63quNB{kdv#R(Yms~Bi4g9(oQwOYZYF`fcDwZ;-e&+u6T3W7QyfyOLH~hV{ zcv{U@RWmFQUhZo-NV~bPb^B)Ma;IYLenRx_^`LpLomh?w_P?t)9#vU4oFt$%US2J7 zG3u77_b6!)XWOBm!OJr?p02gOc^iVO`vx^92i{QobuWO~{!bcylk#?ZolipoAuKZr5iYfc{YDSBTuZQWm0!K#TmjNYXzrs)cQG&h zs{O^UW3-$Pb6!s4t@cgj;iXW3B7S7t=z3bJhFpwR45Ez8fI41>sx74>ekw!_IkXfy zaL5ml)#=(w-DYW8AfCLQ1e{;|xE}b|M;gTf5I`}KA*Be@mJHPc`IVnmN zKzM}j2YhkQ(rua?wS`rnM9N_)A*)+I#aruc65|6j1X`K72zoM*5Z~k)`YpJg5u#T# z1UnK~t?@aOUqv`d{*9m0_V4EBFisI{SFXLr&WLI~tQ zdF3Fs&^^1nyLsQF`roY8z^SLRWCE{Et)_#r$;h|s@RR6~(s*+?KO^%8-RISZ$H2>s zU{yd|BIT`kpIB5PjcsOqU)MkLBt+l-ru8wdyMpf~uKXlS!ZkG8fCc|ZBT$+q#M{LXUTT@!$(pFyi+Z!=WrIl!ht(fbk6;GJYVD*)Qw*}LClLT+2yS_;POgF zq9xDxnSU7MfAAHf5i3~pi3m+?P6Eyb=Wi3&phKKk`PYcAC-FI3!sn7~p9jc`Cj$Q8 zuHDipWtBYU8|yeb(Ipdt&#=;h?}Loqf`0}UBZ!p$r;RqQfsXP)&wO+4Vflp$K6?&Q z;twAQ9bh;;J&DQ?%~cJxeA4^Usg3;(?o`E|Mm8(tG|Ayr6JOM1hW!Z zqxD=krm74NT!{cb)MHL-r<17RXDy8XM(g;r)EeD?j?WYa&0OkUiQjcxzi13nL8K!H zeDiiC=kH~xEt7u3fCSK42D#NOh42IayWdgWtoKjlQnwdQM6un!^>Q};JNS3NxvanR zz__R3*d{xY)ysy%#g0*R>YHm?_pI#R?Qj044R??sFMD2~Kf4zvu{NBA_$usENKfTS z4Gaw@rs*oK9f_aLy@FV(2ZI);S8rim-Z8N3*Dz@+q80$8+CUpR`}czcAl9#Nm*w` z3|4wuio*VcAN5^%L%@{ESF$qq8bp%5q0YxJqK_}=U17JDLBB@&VnLzg8n{M7<51&(7bIU0jO&t zore{7s{$>&?z~!j{}cowSNOHUwt9R85(Umm&g{Vt?c}9`e7nV{JA^-{`()zWc}mP< z`6vz@TnCDyM`=+5RT8M76SsxK1reI)_I0bypU)^%KHehFfB%DUBrq5-5*yhuSmA{K zg;^?iEVP{?k%jiZ^P{_rUv90*a`V}0T|DlP7nH#NEk?)g@D!tQ88(Hzh=ZT!Ipr*U z`$%5ehv&a@uTgn1q`VV-gj@&HX?$b+@rmi(FbA5?fQfs@S1S0_0zft0jJDHE{%Koh zJ}Yt3x&j;YrLThxA1C?y%Im9L>9sWfg@~pxH)IpP6d7j^Rp84-`?w#;l8_>mLOU$b zsHSafe6DIKD~U7^dD|Fa5hAcEABzc6^Ktz%I<)h8d7rUL$;n|Or^b9< zreSTSTbv4S4e zb+4F~=Rivm>wW8;?bgzr-caIP$LEvo{?<~D?wb*f zZzmBM!r>(u$Kar};P##{zdSDu1fuBpt zTQBv*X8N3?HakuultkMtd4Q8C_V4LnBc ze2rw!s6?G6Uf98Phn-$ud5-UQXr(!yslCjt!C&F2N z42*250>QOtI?~TE?4s8%=3ts;Mezd=8L2BMI?lDT` zd+-%YaKTWgiUykY6;X$SH8WzJweL&qkIL~-{r2?12=un^tCjyE$j^eWlG=R)b31$4 zkO%>Vx<_(5UEW5hTP8D@Bgr(i{ZlwprU{UL2MxN=FqS}t>rLg&(9wFi5&|a?mrz&# zoRbHGs<#$=Op@a|-xV_Vm;kCqZ$2nWvjFWH`@0g7A6!LRVAWKP@LcmdKUJmGD^juJxC{MLX2GZvG;>X!!?68TZ^|$=XepiPnI_ zw7cM~+XO<*d*G+10HH=PNat07nZYlXwM@rPmO7qLXF!Qson(VS$82|Sra<}4PZMZ7c8b7fmPo~Zh5UZ z8?C7AAgO@JmB^Lw$JuK7FPee+iUh%!WLW-D7|TxUKs2)mc23L(zxnOpF{>7~e|-~t zbXysjma)vW3S8&i124Twu-3@uWC36HbFS0tID++G@BkdO@4}9WIp8^;aod!0VE$I4 z5;fO>p#q#OGeyM@^ah^>oA=vc>$sD!WAYKOo00&|IytaQ`xdy*D`N*(3eq_ZuzOw$ zIBQjakA4H}(SHCUoigxU#Jzd`lQpGIf8|7aJx@rPiiDYsd|b{%#vtYR4|TP4qD1Ui#tqq>Y+bmSmg z+z30qxeji#D!^@KHArVQG7@eAhbcu6u%r+A~fUC79DP7T;iz6qqP>aA;GauX-0lUmB1ZVAH z_OsO>oKgUmQ;vh}^my3zVKK~m?Sv9DSJi{!$pfW;*{indelQza2iBidfaQ!sAexo| zPK*$(r)0pcX@wB7vWcC5TJYAZW`DlNGS@ng&Z~hyBLySeI*x!{=iCE7!y4GTv>AMt zmVuXk1^f9L2wK_(A#2#*o0AMKbJJ1-)?5j{o7qg$W{F&hT>Bxi_OzG<&uGuwKfjIf z$8B($p21eRx!}LF0QN3t8K+Sl1g>acoYKfv&v!w}2zD;Lm^6TFX*IadD*~B*3&<8Iz)iOh_N{4x&{fS4xV()0>{SrXIL-de)42zC zT=V_D`JV&mh9hz%a_#%5IRC#BbG?4r5j;ncCegYJHs2kk*xSgs93s}2gYC39u$_8}eepBkHv2-_F}GWG%{AYX9!um( z774GGer*__v8MIZZRi0t{)o=TgM;mtgF{f1@A>Sz*Fx&rV%=tyvBa#2@k$NsUcfkLVHNCNR0SThtHEXFUGQ5}559VhEa7VgnO+;XOl8R) z%Wx(0a#?bB4$McCF=BOQNu+&*GB>nFO;-tl$tt@+bD%d&8R!Sg)$+h*Oc|`77zD05 z=fG#tCGgZOV8n^t5G*xc(g?vTo4GIKKD&%d**)j7>{Y)Q0*q_GcafZ(glY&jsRQqM z)!@Cj7`$|=A!5S=kQ&?p|CQIkb#@k5Pf7rLmK{rG+yvJdSHROK^H{-|CMw+`awT%@ zBWQ2>Wx)0DUyZXwKRL#4{2rn<7lEzz2@uW50;g%|u<6SquzBoJ5PTL4Zu7EX_mb-@ zfvaYuSP3C3Tfl2!IUHQq%CcF;D@!W5l`_f#vPDg>Tfd4+@?2)!WB*nO$4%~YO1av6 z|HX`-3`$wndx0f!=eQ=RDFbDU<8}*PQf5q6@yebw(48^63up|Kz{1zkz~Y^H*g5$u ztp3awJmzJAXjTqe?pLw{ui~l#b}z)Ge=+P?S`TjX3&C;5ZT98Z7uKs|%l{TQAW*QA zQ3{?5%D|nyrS`97ZxzETkSr(!kA;`ObzTN+85<27zl>zr@nNvlJPndr*BOalJbldW zu6yaFmM`e$BoKNp?wt8yTI}ZU_T=vV6@1xJ-`n6Sm`~adn_P~fyN+s9%uO*1JRQwsS zy2CV;K){ZzwL=TRdSV_|>*_e|G@89Q9&<}rdS3$v);7U@(+ZF+$p?GQR9N%L0dSh0 z4i*|mVaMbcu$dAM`_~jgqII+MPTY@kTN}S4J(fV|O~%z{ny00>v^pL$ZwolGwgY^% z8$dj*7|f>zGtxW@J2ayi+2+IMua3g{&%;@gbp!&J-GZ>yb&OL=S!PosuYp}vM#mDC8kv z={xzL#a84DIWH+YwACWibOs&j&=}|mlLzjGDJs6O;`J-A>x(9^(`HL|ta0Y3WG?Dr4Y$zkNVR1QH)TfuKp4eVoC>%nyj zmd!RpuyGR{SXU3nEf_IRJqs2SPO_651J;w0!C`tTh-RmOn?Wkei0?p>umO%+)p+L} zRT#9^|D-}UE`h*b)D(8Sm*HPyeqc>Wc+`d_aQ?g*Hmg^{mJjd3?!|Xt-w>+`8rkakE=YB&z+1l(r1Pu5XUQGz-?bWl8CI%Y<5uLF1N{Uq z^+f2X9JJI?J;Y_Ls7=fnbQG-LYhugy3t&GbnH^+2OSN-BGQWhqL9isEhGn1C?29rY zHDsi^t_^}$H$a4W3xus}VSjFffK_tvSyT?eYpPkwUkSbjmF%Qd!#?(Nht`*a``k>h zo0I`A)3aF?n+|3Z!eFP?aR^va0It(2!SS~famu?$wP99*>Tv!5>mAH8~(xn2clZT5LzmBLKbNSHi8lK4_j##EKS?8yVYQS@cx z8UtI@8(BJk58QM!VB7c@Muu6O*MO&P8OuPM*&BjouZD8i%ib`7#?`Qwy-oHQGcsMt zvRn3630P6XveibAu~hwlNjvx%RKf10g>Z093&d_G9T$tvD*Eta`X zRSAG)ujj(Hj|xFF?+kd(y9{o#&w+Se9(XLg12QAbLTe#JAO|n@wg@s|>HNkPh}iHQ z_%APmgY3kFnKi=E9c>V{z6rb+-G{I>55U{75JJ|<*$FIV+3g*$7=Ik>7`g5oe+F#7 zP2)5YYwZ}=FDQi_U)%+UcOHOX=zS2pQ4YIjH^I?O3fQ+)9(ygaV=3L-1VYc?{^iCm z4sE+B+h=k+9B1z>`!F1|RS$si>-lUMUceHwIWJ|MP(pmNnGffMmQ*Fhmh6v5VEQX{Fbt; zl##Fh@(M<}b=>MXbWH;U88t$vaT`cMaayu1HPo zl;i_Y(DA`h$D1ypD{me?wBar+dp{B;4R8k?)o{=q6wi{NYA{i|3zowhz;0v{h{v{q zNcSQLXU4tDCu%@Zl}3 zj3XLguW==W7`HI;t>@}peU=t;yc1^H0=v|NatLE2(x0wA(h~} z^ghQIK`ZMZa2fk`c|H4mEd;V|-RlcWEtq zTQozcNi9Tfd;k#}+Zftm?{Yb(vmW3269lfR1liJ32wqbLksBT`(yd`{mPR47L&PmDOIx~kY4K6{@vN{ld!#?}nA7SgTa`sj%0+ZM8 zv5R;X=BUPij>Ic;2MIby!)824qAEbuy95) zXulzaZ(g;5X#)dU*6POX(M(qjWzT0NtWqmvxB*+$tHI{I1_(541vlL+u+%&TYrYJE z9TVfhW7ZXLoR$vTzfS!B*?SM5s+P4~ch_HMF9RwFm=o$+>e6KnC?YvXFs-%se{Q|^8|^-)>fZYAxqsSwuQ0o+Yfi=-a{^;_ zzx}*lf87HKx_3})+mEaxy~wugWzd#r^on$%pY&u5`8Gqypkuj5N0DaSPa;Y#S^Fi+ z3W(HviA*zY)h9un-fI%^cPKeNgb=yTo&?n%xj+5di@w0EAg7f*2vfNMpS>60E7^iX zy+@2*Q}l;%+GZT5k4+-O^gSZ!c!AXz@~jB$P5an|NHuwl)7BqQ;xNrHpL;F!P%m-EKEeG>UE;$`*4-3ZLLnd!@JcCukz}DunxbU;%kiV zJrSwhQWdXz1N(o7VFJ42I}Z|69|kj9zjMMadd@9AlAVdHW7I5Bq5#jQ;5vzFvr_8vpA`z&0FY+u$3CaeLZSfvC zM+n^P`;nmEjU;aI(UCzC(>|PW7-7yh!;G8c8ep;3Q)Z(`IsA4qT(8UgPrua?q|{&@ zEPJzui@nAkxJm!;019nB(8w`BLfOZH&m5t0G1e^l=Sxpa;jH5*&e}|o;0_V3zDJek zr*9XIaKF@PjD+_Uk~JU0N8$=R_B7-8)+z)@cfeb=0rC59BSEVVfg2{^vT%&Z^&u?h z_rQq%J~ZcCgx1_3QKS1hD116WILSaY)RFX8mpVcL8iCy&Xia+-`atxth&? zLFD=dCxl1fw7eUM>YS~A1#bc+FR6NjD7C?PcO6`I)xr9w5+v)~NB+?lNIpp7YSNEF z>v0qxpC)Y>L8{?<6rC7D43RIFZIo@^hg>4md`nJDhnX8rHtgYC^JI+v)1VqB2>j`{ zUV^sW7YJ5t4T{majRGznLiV2{(cEK$EEJG__#LuLhfwS|fl?CM94q?S;w{dc7-6sH zSq{?$A0#2}qvLN-e1Z!T+(v{-7yPBJ!%wOe-qM%p%V{JPMZ|U%_c%FB}&1 z!&2}S)ovOkTUl~2w+}6sHYPqZl15c8HghRS0=wfoPaIxf27kF5aFQtPED3q+@nP@_ zZz(OW^6I})uUGY``0cAb=PFy;>Lq^;G6Eq)roOCC{q$!$Y@gwdT{C=1SVO39xwE?K zJ3mITTtC$3?}P#WHI{;9E8Gje??;F#2a#ra2Y!1m!$GtHZW8BN*e^)tCQfXtK@sUf z?vXdhGJlJ_W1NQcp}=+sXNgYpkB%YFx}P*=l3)_jb_wjZZ$N84(g zeir%D@2#{(KqSv{pdjf`H;p<2$h90~IA7^Lg?y_K78c;dw8V7`7kqv}h5HzaY)4S- zJwc<-2x`5)&?xl*70#nLZP88k|1KQ2*O9n(z-`ZE1S+&3P^lRyMo*EhF$K?6LvUKq zha-Y7a9H3W^yjs+g$~lQQdoFEj6{~Zn*z58f*Vc6W^f~}2lg$>#esDxY&~)QVFMU9k!Jcgg~lo1wBajQWi$392o&(IXdQEtOh%osZ$TfdLBHDu@>j@S|AHz%Z3cU8Tv8Avl74E}BvL2_bA0tU?5Z-GCVK4lS z<-D5AzXP3l%~0hlCrXW`8p|qYSGf4kZW?j9y&JioxkkXnizMdx!E*CyBp-N)Gp?^A zZeD!D+uD#<|FCte|I@6qUQdD(_TMK_y#oF9ao9P-8(U{Mv)!Y(y7kXa*!mqOpeOPD z|2XjN_)I?*ca@qE#~dSDDnGjfM*I(PRIrBtXb2}3_9I?-nDpQ|eB~~|RxA%T+ltww zwVP-o{KRg+Pr4aJR^2GJ??WNcYNmM)k?R1m&H9mVJ&e4gBLrikD03yva2`YcF><&D z1Cv$WlTLs7qm|ra{pQ8TCwel>-Xg)^InqqHT(nW-+r1-vA0)A*3*|C_QujfWoR~l% z;eIiVN;MwSM6W~0F@6oZ&6V&LZ%3$n7d#|rgcGko-2NMgP<;*mpN8PIWD2%I-;$IK z`ENsgPA$u?6PpqCO+aUId3P~PV7XD2YXssmBA5Vk!FW*;+e2&f5vbZgcI0hVvHSDz z{s+IT;&nD&{iD>0v5)`KakftHnAnaI=uJ7&6J*Gz(snIYIY(~DJZ z5^L*s&P20b*h1%Uiv{*@uXE{FGXhztfCHPovvZ(5w~=7yCai^@!DZnPyw?vPQLmrv zC%|nd%B{e3qkiosO3$TlAyBp*sRwVP*zpxIEnlL{X#zE#pOJ4lOcXneT#F$R*Vm}< zqUScqv-e` z%ALkh>NJ2_mm#Fm4pGVv;3{4RFWEY>1aA>0{T^=1`*2v`4hic`m~LP;)3<2AAMZoPkykwxZa>TM)b#(Oq?z=XSGs)cDY6?wDOrDRLaV}M6a{uYD03ab zS*Ly?*g;ggllZ!gBGcd%0wiw1aVJ>^>1*(oYC?c)8&XZlQYiMqf898o7xt3{c>puA zA$oJ$**(9wbUB@qa8E2+*V)qoFmqqM66ueBR8kPIYW)P=W&4l8cYdx zP6+qIZOIT~l*W*5!rddQ8IGbAu-$nUo}$fg+1?E2?M;Z&xQDaWZ;@m14#f_`k~>HM<>tuO$W6mK!B&9|Blk=|5v9<=Z`&Q_LHdg;)2rysBoSjitRy-$0W`= zzQ;xXG31%NMyUK91WP=mFQW|}VvUGUe1I&=yGYW1i@?nja9lXRtcMX1tl|9YP@H`l zDtx6xsu}Dq3R1IU*`vaoEV3+F)Hpm@I6#gsm1-slZ5*5YQsB#F;R10Qouy`S?@5ID zrXr*oJ;p_sPZ4#2<35A0KMM0YDX;z(Yg68P18=3~Mw{)mIIuPg67zhqWrjT@=7g|# z>aLkS*iCgid+r5^*^zAWN_=J*#AXN5InL~L>A&5fWGBlZk0kdO%*d4s#c^3WYI7=K zA=pd8Is~VMJqTVuf<*2nfd{(~CVvY-vbR{ydVtJzSZ+LvK5*wvIt@fM zrS)12zn|peby!~gP23IO-lx??)*q4s74Ka3lx~6f>iTc_sk3~ja*zIyntKx4W;hYS zx>I{6H%EZ+(|0x`s6?@R0W2)QCbmdyxv&5ibL9k<>sR9B_&CAkZkr;{m(9eL+v%TM z@@gym9zGlTk;>f$>hKe|iPs}V;|)&iu7KOFD>$*`0wU#}A>ZN!F8B_k+IIkD!X z#@jN?pYuWh|J8CoA0kyA!)@ixBe)##5p8k5px*Bbs@#Xr;5+&^aeV-n-3{;*Yi3_e zIJa}o(RWBv8-nO2%L-zkIN?dw->U@4S=c(d< zbE)(CY+mI)-cxAbgEF^%BH1xC_>Un`^AY?cI^npj9$pen@Yr(&?oxHgws?%x{iE>v zVU$M5XE2$6m&IOn=3Rp3ybJ7$-a9Ls=rsT;^9sr4L@+DEG6-h)KxTFlqg!r87nl30 z$d~&qR4_Y*H5i#WTnbk*l=!o$;dwE-zjznR9Pr%J20t48(v0pRVgGBy z?3#k@qDMF;^csf*?!rKzlj?P-&M9Fc%84SEHo~nO;cN>RfBlvN8_DuqcQT=k$6lgS zZgPtwRT(~_T)r6Wq>)^7*0-ELMzgcSuwS?l#}+)Hzvm@RYP2I%qn6SpOp09e`%qBrIz;yW8DdnPBShv7+;%syow6boA0k=r2?~z&Ax35b zp=-Y2m|!eT)pMu zrPS9JqwhcR;<3E?53LWc_iXf0ZK^M_8cqw5y9w=udC(JRf%?2MYQu3jxS$15+SlMM zc^g{%wbbULAwJKKg#~ua@?=80W2P&1&T@z3oKULYh<59YZ^yTP=fWm>C8=+4E3&x0 z!Q36WzyIX`xk+Sh+fP0ICRhkQh2z3r_-=WJ48s9rnLLA=< z*Xeon?_J-%8WavQt2w2#+-t~gdjlNB>qsb%LvBtIOqSe)@?2{BWZ@k)JV2hs3wV*Z z%FRuNq<|k}_(R!b6_-*aKQ9HlXZuj~BC&PHZa#PHne9u|>I><45%k=Tfrb>{$-hBI z9Lv7pM3n;;4o=kOl|xsc9)|_)v$RNuMQ;!+(T7~iK6aOAZWpXj`CIUn?3nZxZFSR-cP2$@68=YsvI;D0{w>EiMRz{M;1C z^QU0zOnVa9lThSO!y(~j78)=Tyic~ukKUKWNLg!nDgu=*AzZ7mChJ&NTIac!3Oo_u z)xSs03vKn#Tov|SdATR-cAbIdl2m9c%76sF7c_*5p(AvWxh-{pBE%?UAp)8Qa(z6t( zFK}5lGP4ueq%W6KzL)xo`n*c$^IwB5|0UQ6_rQPkDAF`PpxkK)soLG}mZIa^N`mAB zoOp57Ut0;<)*}!l_d3W=>MDHpbi!5a0>ZT~Am<&-YN3?2! zc_hH!LI-klH{Fzp3Xg7_wS9}jYb%&w%JE0B39JK)>ZqMZ!brFi z@tUuYsPPth!sj4HA}S*gitT)MM5r!M6;6k&z)2{~r}jNJjE=ct*KBueo@vEGV%%hw zvcM_q;q#`?i(zvR9F(wyIOO!W%7q5B1kS-s_#Tc4y`cIEUh9UCa$pFjtRBEes;MpC zaEKRI{nam}m3uDYw)=8{pF}&Nw6CJfVG2<)18`qDf+Ki_%EeK8r*& zi>Ni7&2Dn3S5kbD*e6)Ph*f%SB#Wc&nc+{PaR|{Yjrt4oNnAr%I6#3vmCcMw&k2Vp zpFdRQXG29W8`|^F!FJJeSS+~@t@$-jqETI${}hpNGE{^zpeRUUyCfd=d&-b*dKcdE zHO(a_Z#a+iP4PsQSN~J>_SI+Goz?R%>a2==Z?mHm5o)(letZD+zT-&L?1RdJ6zt@4 zf&#TYZNVC-2^2zZUK}iz-XVAQ0`WSJVX(NK03Zf(LLnrm^|w|$_O$Ax?tj!%Y(Ic(-7oN1(+|f5BQ$EhgrQI?bOr07 zKED_W0?G9FZGTs8a!Yn@JPQ$Uiv?unMl-SHVpOX9IYg_WbSxH1H1caMEQF@eSrXP* zSgg7Ub-{cVCQzE6O3w>mBzOxJ3m+5J=F`ZYgS~T;sbL1N_bQSos|cq;RKN)`!hWz9 ztw6NyRm7XL3LyHa7E{OLx%q(k*zPb&vJys+#nL*a3bLdBHC~Lg0*qJQ0Cyci7qj2?qYTdl;;&< zztCkI7V3iif;Vtl@_sU8S3fVV`kP(jX@oid}rpkl^=$ z;krz?%9bNu_hv=vk_D(i($6Bi@7MZ`FV&`>O+>%bGZKWnzczOfk14TX^Wk6 z9NC`6asts%m>&z#dG6F+!yrD_2jYBwP!ddr)Vx5JJs>{k+oRs%3O4V+Wz=wcbnKkz z0mV5vP@Q)chlFpynuOI<@NQy|2ye;i@1~TPLnL6^+XD9`lVsOlkv+MEgY!F}KChgJ zw1_Nw9*JirON!=bRDFICTO1%sqqExl( zL1#qaB zpwd_Qy-l|o@r7!-x0u}?T3=BwJ-X7Gl~ zE+Nl!5M_2F(57>?@!1lM20?1RHzfJJAuZ@f?K23{0>KcQ=SkG+OFsu=>nt0hRewgV zoUn3X16lqU)*sXab69RTN3GmEg#v$8kB-0vUR?E$Qgj3^n;S2^+H+t*6AmqHf#}R& z$nvF-rHRD81vyZfpH8E1I;8nxAU->otW*inY(5EO0yU~2Xf7;(I-SSmx603tV|jku z`y}TDu+d#fD3MJLSS@}5GvSBO5I#ennMR~rMvc1wYQmW$tiI4(mJZd0Tzo4W@(aRP z)m)kdr9~&9x;Pe!ivw{&{4CsLOIyPYE*9Ua$mQeoRbv&2@yNfDd-ec4Q#~ z(YfxdjVlVpvQUBS+!!|D^=*#gB%4=I7tEQIm>m%$ClJI70sIk*fpBZk!9|yQSRj6O zDE0{!u~ZTz!8Ee+1vK&okSG#i&Iy2uP&zx#k*BIqCX3U`%!{P+a-g%Y90n`OS-J{m zmn7!;lkGYOvn4lRvGg9ah+GdYJI_*Jl!Y>&ESyXYof_c6R3g?;77mahN-$V`8ZyE@ zP+1ZM)umC;SWHyBA{oY;GGVki2FJznZ+fT~T^#5c<89FW2dRb8S5BC0Pq}wwQz5K( z6(RM&3)Fi~pe1Aq^+7|p6gGu(Uejz7=}M=sM6uIIQ0_*Z=M?IEh7qv0mBsWW1l?Kt zG+EKc#E^r5AhEYd)p?0P@t4%5v!NgqNzN&l2KxvoFNlZE@>48pU>6^^aKMd`ujm|4 z0)TXu_sT6IP^EsMFh3sqmy|(8Fat^g1Pp@N`EmjYJW>6lmu)k>L=@&F6sS?-(pqo^ za&r>N;uo=5PZ|C&i1P)q6)IdKQ(KS)**P)va}o;?=q;>d@l)+ZMNE9PmgKMr0JVi_ zEM@D+lKZe;{usK#)ht%ag%0!=*FtaU8K^Euh78#)xdnl27WdHFLZ}g~sxKyzT|ktv zG!Y65=x-46!GX0T=8Hn0yxg1JmDWl8Y-d5xRj&^NUuN+H=y$qgwWDvVyYjh4gCCN+ zjn`$tWm^*>Rqmn6VF;IfKjKRC2Q)>Dp&{TS>ioZ=<$+j37ZJ7+A!?Kp3P20wFFyVl5a0-Q@*rgBO+gS=cheu5H&$KVArcSN`83 z>m;&QApZWog`7afu!R8{3ksmWw2}q(rRS13F3g4e{8*w{YIt-GH<`szuh!yxYIq!x zCPIZoQ(|r)S+N`(THFH1HE*H2s1jNvw%ob%;j63u^vasu`!sft!D$d z%92PDSYH~@1DJp+2~%5NK$N?b+USyW?4IKcjYTA~i&LPoFqYmE!QeuAZusPGJ|An(yUL=us0oMYf+B4_PU0;%V1x53)o)ECowrNd`+>QC*l0MS&C|f=U>z zswF|qhV1-sXp`6)uc?9QifcHr>Mf3~d<0E8CdVJcLJ6FWGFV+mjg!bgAOLd0L<}NX zFyB}Pjpg(jk%r;gd?JVt9NkzAll4W=6-mXxwYgATMg+Yq5(j@shyMCdm~Tye5U6#& zrn%yQ8c&>l+qF4s+$37_RZW=kLnNpUB2lRqQL@hwEB6L@h65qrc#y z-zd&|d_twm2b{5*Mve0ql-m!Z;LrftB0l1j(QBBktA(_%7bN&SVY{IV#!FkEyQByw z)^_8R;d`X(z9Ru{hW7F_Cahxf+;QmpGdQrS0DA?)Aw}e>ydVxTf&l~#evn@n3Q7I| zBGz0ky=zipo?noTNIowFz$^d$VzusS5VzD%V{s-_g;QC|2^TsrTvC7iONm_5ptrmTh9YHbWy}5*r=h+e8*V?mhw~4;Fj#t?&W(YxU#2G!xsSYp%n1aXak3e+VOy^DtOeNewv*`)}@g+hrxJL5=?$dhT+Ee=SglC!iRb$c_RBOuYHd`t*CSwi7K$@&dNFR z90`i=5ib6SNVNx%k}r`c-_JxgOLqXp#|BaBI)LWzF*Jnrk+^FJ`I=GKzDHwIPuk5l1Fyy42fzcWckC%_MgSkbuBo$;xSy;_u}yC z258ec2bPz^YQt5?3x~7DtG_ZIN{hp&hT`a^D#$PPV|1#%A_6MQsBwRv4ZE#%B(gbB zrJt3T2E%mYX&l>93H8;1&{!FbeJdhi@?$QHf6T<8^~um#8w&fqIn8Y)uX(qc`8B3i z4Sbq)HD&B*(b0Dq*$3a?ockDZ4BsI^;T__n-y>S`4I)WYW2Ac!A@vNo2ZvDOGJw{Q zk7y)XZ9VxB&5_e+4E%~3x6i0N{uyOfUs31#85LF^Q13B~O1lX-h}L6|fCEdT;s$)X zjklq*q=?#JB?^wx?78kn$u+ab096`1t}qKBG+_sVX2cU z!g0JMtGx2}De^+m=0vVNN`i?nSXB!Bg9W~@+)~EuKNljq~=w5AAJD-#mUd2v-<`A1|Gs4q?m(pZ{?L#xVhaAg@(7bd`RT@#D9 zaJ^g zn+tGkTQO{QmB4s?9(Ak`=zkvz&D8<#GQ69D``?TU@&xXmQ*Tv$P)RlHKNF_>urW&W z2?C^^!hJ(O&X|8jOV}r5X!Q}LK1YJ=0Fo8@5hM4SYBy5U-l5iMoQQP-*Au>=BkmKf zM1IEQ@Xx6A{DiZ1lPIy7Mxpr>YFtN=r8SH?pHVu08cusIlid%3>e5J9ZM*{KZI5VR zFM#9r>nODyp*l{KS`2wQhYJU2uSg~^h=Kf~U=r3099W&(X1F1P7gyz#e{7Lk93f(` zvbf;z_vO%8LDaam0@{mDLt|+Q4A-7vL4QLU^);4c!+Fy)cbEvfK}{iydIFF1|Z6u-<3j?FU{w z_8(O5cf8%2*$3UWKF}kpf8?jrFyC|rMjK9n+x5sv^dedR zQzWdpFj$|0!y8XQ=lhf3wwXI2R>?%v?5BK$sdv!p39#N?2162N(@nW>5xopI(KhNl z!PvJl5cYd>o3B>A;N5EG?^uW4P0mesX^ODjQ`F@kb{;l6t6;vN0@mbayhUHZW7{jF zDSSb-%QQ}NHwWB1jKsbD2ormXB*g*5%l0Equ^UzPV`%W6MxFlN|-Sx;`}$6GM};UbCbC8TMM zvsGNal8+!eKMZ2?U7))rj%w1R#>%)LUa#hrUsZ7z>oPa_p{hrFX)c_1U4tG`sp^tw z99&%t`;E5{B-#t}bq&329QF{IuFr<;o-@#29|I@xY9^w=N>^Fz)pAQdG}i=?pyt4ET^6ji zR4{Qh`za4cx0K<;&N?FDWE|WON1q@1-by<2>h1PtTX|ym-#A${I`uCXv+o&Oi>2MP z-%|t+$xCn)y?|poO6fZ;fz9Si@DRHX@7*M#Y9nY4`2}Y!2av8jiZ}%>OQ0Ju(yx&y z*N1GaQMS_Ra?l5~M}K4?f%b&YXbR`{6PQBviND~i#YYsGOyHu|M-*E0quiknO+gdz zmT953Qb2=l1~gVA!gljj8t{{8;6IP-gCoc}{04SgFXPz8dX|Nvu`)K%Nv?($SLKyo zXE7AX7tvpxS75mIG#s~e;_wfpFkD+i4Z9saJKy5yh8D76#V}f13EgE}icA%Ze>j8v zt21D=qlC@)ANV02$9Ggwr)-AR_97hGkcI;r5@GTaS^OUpm{3}7D}d?dEVxQufF+5s zt>_t;Z_b0owp(gPexdg#`AHifnd@1ICGe&H1Gq?m<}UFX%I=WLZC!rlflyo-=jmFUA{|Rjo6S$fD8SU|( z(Gu|)&0)Xbf;W-t@vkU3LXSs(#s&AUIDPN~&O3fWD+zXx%1s)m^I`ZyHV%JZi4&V| zLw7|stVvL7oIau0b`b7jH|h1Pwg^SuT~>MJH&Rp=Cy4k?Z(M`3~z)2K$)UrHRN6AX)t&M}xk7;n&T?^w4r=Ynygv2!q zUecFgur3kiTe7f!eH8o^T41&{okTYd2i7N$Ko`POrU3!+?Qj++TH3~mb2n<1&eJ6MLWfDnID2O?X?8blYllXmSQmDF1`|t6uNjm~gZq!)Dj1 zI~MePSZ*#LN^!V@ zoMA+2u_X^4(nOgXGf5b0;iuS4RGI^4i5eKJkH-lyqSPHZ@Y&k{lT8`07cIewJykfV zc7su^?apEx-jqcIb()c}&CYVTN;JV$tOfQv>TrDLdANwS&}TP5XDt`MO@WjA+2)Sw zZY7>*{`+caSeL8G#<=Ilcb>-a-6brx>L$?wf7vb~$2{2Ys)ZwcudZU3ad;gKv^$y* zq1=lIsUcL^lEn|6LZ1EzQkBM#sxXWMxjw{6_aaa411>mC5upy@R_a%DBut|%mfNu9 zD=zwcMfC|1R`bs&F#JRU`vrA=M8GDasQ3PWQ-*J8u)YAJP093~o`S)O3fOMBf+IiH z;H2!k$qfBBLHRn9ybu7d{Pv6f%G{una{ZHjqVM3a?K;fY*TQaV3yy8R058c~FxhYh z2iK*+jI8~!?S&+u`Sd&!hCjwrhpnK;M7T+vN3c>m9nZ#bu_8KthU|ScTqLXEuUwC# zJ9FV7bAdW^Cj8_ZVX`@$Xtj*aD`V+e9JzAD>MM5@{&LsgE!z&;9W_K*<#3UzLzwD4 zmLF^UV+I$R=(dzh>*#qk$O{$x8+Bsr^S@LicN~q>ZmzQ1k$2BxOAZXzXTx2h6;9%f z@Q`eQuk1BAN>tJJl@I$p6*RaJ#cr!W@ZKlz6@QK}i9wXwki`%Dj7*}|Or=RA$n>$A zrZ9#a-4S+k!H%fUxSq_#TR-DU6p?GdN1XHeMB+-sYWf*@2S4Jh`4`kUf5171Pq-EL zugEfd!4{oZkhmMJ%Z0DZ6BeQ}`=KgdN2ErC*CTo5cU7FW4T+qTdtcxw`Vcl-8sRS1 z1(!XYj4+PxK8FMAl8GwoVYR)O1Tq&EM5vAuWw0d?^;Nh8N3m+SOPz!9rbH&9CnV0m zVmk?`LL;1{N@2IB2v$4u>3yf*y_e`$>=aIjmcxlUxWB>`mLuyS(+FqD^K|Syf|Rep zQ??l{;!W_A>x8p-13hnqx6Cyd(BERPE&&I=Pk5W=aXECTcanFjnZMN+w+1)(X_r@- z{gi|gyGm(ryNnQ(M|6#EP;G~oTr)ydZX;6jK927pXR$pW`s?H9JGp{rjb}u)*AS&N zh!nL^T=e{idjAhZt;2{E?M4QPY|7pdB*_mU-(Vb9LZ)#e@eA6MCU7nOE1FM!!X^K| zpvr-)ztt4-4}PNh1;s}`q4?-9%8yN=$>(R}m=2QbDIf=Q7H;D0u-ks6&286hUR;$| ze&?YAA_uKiNj)|{U4fhEb)wg59Q+{*MjLWS46ETof@dR^LjqUd0B}Az=+uX@i4AF|2pzljs)0iRjjg z&h?PKM4wv=f29_Ls9q<5y$%-=bPu^Y7LRolyNCe!E_(lCgztL@XNfxcyHa4aC$H;5 z)-#how5ZtZ?j0A&a&i)lNIBS#VC4sN%{$2z+(CqP7Y$N%aFed5L8^_# z!~+ytV7-&RAE^uQl)i#6h1Up?=|PU(6zY9GW$ zXbzepVx7jVl)sR;{){V;KeO!x&stBT(s~L-#*@f7Fo8-U)-DU<%HUFN)A$18uRa$-lTx$Tbn9(VB$SZ%Gw@ttJRcjhtLwAh&e7ikhr(E^xn z&W7>UIJipHAW-QtJY;L&qi}%;H49d|v*9CON4CBKmOIjkL@%@m;m>+}nsCrRzk-mtnW-9Erv|Bxt`!f^IMT zWFNBZ1e+bD_k1-jo$IbgqX5~PY$DBJPhD5B&zpdezA3)nyQp3)xS{W(T2}8Ue!A0Lt^y~uy6Bp| zAYpxp812`H*!L3Any(O|b{C#<%|x*`i1=?IT>S>z_SO)s()U1O9HMp&o-&u|x?Uz{ z(uEYQ5tjJRS^bKm)5uW%fJB*oB+3pTokTW$-w-bQeMEiW09*3f8a0g$I=3l=6Vkt+ z!fqOQhF_3pFom4`pV1oj7Ze(g;(E-#(rd$Q8RpM8caCgi z6A5btcfTw|s*~`^H<10mKpnM=I&dw#h+N%>YLAQO(uG5AyoM~0#xe}ta1&R=8uSU8%PLlQHO71L>r*eMr2lxP{k)m zJw)`X^B(b9eTY#VMxy2b;&flaTka}}NEb4U`U^V?#`TBaPyg;j_Vw+tb*abN)10Nw zcDT@W3{~lXi{vHt|A(qRK$O-~q#F&;HGhjlonE@0w-KaD!m4(gxr0c}E_f@}(?Hlj z-x=pD&e4EbN!PfUg%aXaxXoCm&>sH@S^GwjC`Z><<{P!9DU2iEU<{p!A8|YFXS794 z;a2+3XpR1gOM$=OywhJ$ZTAJGmYlGTB2#A!7d$6Xe0chPliw#^T$NXN<=-lPa!qnR z@(n#fO3g&8NhGkRVY54rMDRQUl^ftBUWz3BTVy%QsFqOYt-;Y-?nrjT`T0vU#VNINuu6vG}8m?wzUdxY~rBVKK#Z}$BjM3viU zJj0p${*12luehG{Gdk$J%RxV*C4i{a{xfP%d_?Ynzal|-5NFLlOkQ;R z%-af(S9s;$6_1rDGG9l4w8IIbY$XY4H4$hVLNy!Mv1pA>oRBz89k`x^wiw}B z&FmaknG)EEXORfrN4owK1S+(^Pw^t+^@&=Qn~9_@z(ejl32+zL+zxokUm)vRPn67A z+XiM~{S`aO`aVXHEp>MNaikC-rBTf@oj{h!AYyf&QhiRs{0uRA50Gm7xFA^PLREA5 z-QVo3X0Da=YWb>G*83?};iP&yBDFecKx=}xLIWbTJBik>Bh$Eti2fBa=^7**c#Zh| z-N-Q;M4a9W_{d*@A6@H{tE^d6FTCET7y30vhTm5(*7$7jK5_H zLhJtQ7@N(A?q zKKCAy44=SeNA|t5L7iUxJ)^&wUAJx&4{8dBkfyL+ZhINIB4lLc>pJ3iyJn(Vvm2@&Q>?(-p>%sxXEOm2tF%eMU#jXBH0V zNce*53IB?gkpGEhzptpWpGJ}C&u!($K5ygo5?tazv$qCEb|%7nM*^Ir3K2?{G;Cip3FUQ0xBg0Xh}5}CcAlt8 zyOmzMf|P@gNeEsbl%B`x+@WLFkYWB92}Grdy04LAI*hpeFOhv{0I_O)$TAv7n(;g2 zS`3j8KSP?~TN2erM6OQ|O=25O!t5k=mc+cGwKVv?*YjKb8-A^#TAzFWP=e9b!Wga2 znsk#}h^0X$PWuMjaQW;WN5Mk5F`c5NRgeH1NEk|Mv+p z4)+k1J}1F_LD#nf*~YJsV)y|5>gN%uOV{|oJ%p&X(sjH|M0*=~hewcaJc_2UDO_}) z!YS2BCaxJuACR~26G~0Kp!MVw?xg*UdpTTa;1_fz{(^I!Q)u@6OHYZ-&%C%Qukgx$ zXYp66F?WkDq{5BE&{(`mN%@zjcjl$S?SjBgeMtJh!jQ>!JxqyfeF0TF!*VszWtwaGSl zie%$kNH*$X0}^+Q@-2H2yZ;^vtOt;5)r&&AVH#B4Aj_u!3=o)e%fz(6yiC|mc ztyoI~&UM7jEIPx_<;ncnv4abYzh9qg7SGG0AAshzhCi?uW$-iz0%_(TL4EQR8GVqHLoH> zy`HG_D(oe55w3QH#Fd0X>l)GL6Qmt@h#=(#66F>mu)B!gPn2eG4e6$L$O1n=010&N zv8P0(kC0+?AE!xBGmLsrU^Rp?r%@Cf`G8`ZPbjgS###Gexec$q6)@c#54&A?u-lWB1G@KUHCLglh5E+9s;6G=psN&D|2LH`C4xa(qkpM>*1(hfdE zmI+-ygXajR!7Ib;ISKAF`v2c^*%FA-d`QImgs$~{oHBcfaE&(Pm_McW--DC%S-Q?Q zk!*0A1|crwatEmfeROSyQ1AW)o$H7}0vkR}wi@BUtqk z(n%n=i7{WLYD8*Zq0Zh#V)=rJNwUFRqOvNlhktyks%fOw(7$H76RgeuJ~e-;v1NM20C@U$Ym8)@&!yK93;P z^YB%yftOq*0u<_zr1cD0hn^QkX|>g)**C@4r#~^fd9hpO+0DKUAI2vCOeQG`5hUQv6&Is4Mj5r-G4ecDlROlM$-$A4X4LJ58b1a|&g4 zUvSQeNbC47$g>zm_K~;9HYZDL{t}soU*nAJ01`>4i>>;QbnrT|4nJVR606mTOrkh0 zmKmbj1YeaZL};}jN%s-`t}6)LcL{!q=iseS2`{BmBFgg1QTk0~;Rff63q89+tAk#6 zRmVI$(U|tqq9*pS-Gzi_HWw3LST&{gSQPu-52*Be<(FX6mK&|zQI%?V|4bo?VW!y~ zoH_msr!0vkEgm39tq$QTtwi>XNYd{jF{SHZ&`HF3i>}diqW%tqX&zq6+j@LSsFKKj2C9-!YFs5jZN^CwjL>}zM5s5AZS;hQ zwTrASQR|_bD71cwY|DEnuzXEoL&wb?lQ`ZbI(vtV!!J?dIEs=JA5i7+7ZTPlR6ioe zWR$3Fg2ZYNnoy^fP^N=u!E@YD&qAz5v_FfNNzYlFWU(J1|&c_j8ZhHnt4QU@PdI;M67@jAB=soTol@2_%>Y&`ufI_)H)O)Qly zT>T3D-#1yDG>qsrL7$!_)B9|H!IjXTaXfC!DEVuDtZSq*d~&3Kaa}aL1-kTj{f5W~F-f%m9kLmWbfSh*+ng`BMWL&TWxm96-M3 z1Sz;DcyNhA*}z3qhb#)|)P}61o)lJ*|2&cF7V1LxN!{+FPW=(h!9UP@htNfQ#{H{b zP!sf?l-nCLN57_HY$4BQ3Z;RwL@JYL4S9nyuN5Ng4I%L&j~P<0Q>3h)A=P0JNw&{$ z&yEzeWhbs$wjtGd5Q(-u^qmGMRG*NW13%xS(E7G@50T_F?QcX5h3NMjheV-EJDJ@O zV*jN3N}>*9$aEc(Vqd27IO0yWka}JxLVZDD`iP_^QXHNO$uj{nnO-~DPRE^;bV0t$ z0@CPx&bgNQ&7(EqHGQ6euE{D&{7K25e~C8DKHYHMj@l!oZ=}yA z61}jEn)9UE&(5JNa9R{_)mbL!byBl?s8S!IHS8k{X+IOeenExf5sFV9q1yI)eeNIk zPALDu3KaZ;QR+P}ty>u`!!or+WQ!`lRU|t+LayrsDoK$gIrJiv-Y@o^qfq`0DaEfT zf({K4B`L3(&~>z3+(%8wTQr{EqmcM5>I42N>4Ca)2e=>i1@|w1Phsv$v}$%~`)$+( zzmgm-tGzP6S!AmW^gNGpBI+z6xJ*)@?2V9aKTe;wfa}(zQtf&X`{xD;$&-mFZ=LC( zM>mSxSBNB^6Nx?{GA6+oVAY2_)jZvVjA)M7L{0b{ zo%13JJ!eoIxQ3eGHRvMW(Yd`LmHG<0n73%YctB)(2z~qq6bCGzJ?bs)+CC+s9ieOb zO3pjqbDVB2Q>gOi-1Pw|*pKLp{24C_e#AiHk0>~~H(Y6BR`RL}6#SZ?*O*V_IL(+! z{TD^OwuHQ+aGGiYcx~M}m$G)cLJv2q_pelG1#eqDCutZ92naJfON{F!YJPp#pQ0z4) z?M*4RBgpX>CuKPyQ)8TSWd)mTI}ELDAGG$pq;l!|l2T2uc}T=MMEeYhZ$b)fljk{2 z1U`p+w|S&GJx8%8h2Zo#1@wEas}XnY`{?&sB-;!jkq9%_;|1=KYUN^8rs@Tev=M3c zBhcE=b}q|A)MKP(pP|xslL&cC+SeMx*3lTbiX!hBQTMgyRwd-`y0VM5m_2mF(Ye!g zYKt+GQvHOs*gaCPTj;*Lht}{nbi|eE?=e;U zlX);v8Cg}J;8%?ln?ZHD-MEQKj#X=!&jPp|sfNh3J^Ced;U-BJ6nYye?B~`hBay=< z>WCog&%Z-c#1UGekI)%?EWV+gM6#`ndLU0VgA7u!Tv<<7jiSVFiHLAmh_cdeQwm=RXC6t& zU+lU{g!mX*B0Kh2V8YFJofSgN;DVIhfE3HJRgXXKa#u8YVdm8(7T1lf+$NV0h@ zeXQxK5jw_W$={ZGt;@04lYzG@^fb~aaFqHB|$*U?*@LPfU z8|@#8{f*iRzZL0w&2$+;ZP2=ezPhLlDZJ<|yp#f0Y2X}Mqu)S(?ErO=Cdnx_h8>|P zY#;UKj?jDk3z5hNv_%uiM7%_G$R_Q(i@I~KNa1nQ{WIhenPxhTN&zj42#`AllI)+z z2rv616niXFC{CgIsryK_A0%~aK&s;q%Kg?!Wlqq(FC-^gva|lLEFgnHlX3+tKr&klag0epy0QNmhin3jUnrG zP2p>#4Es@eb^-Zb6VMS!Hk{i=y?Td8caunS9gnqUw8tFDAVG5kg})b%(G>E%cnx%1 zqR=?{E$Sn`qtJLCO&4BE(|tXW5G%imvok30m?okk0uNZC*Onwtnqc(=_v{T)mFJM0 z+oL#7SsA!NA^JFy9iAb@W=KA}+;dHeX6cS&@}0C+Po>kM zk*-5a)F#RTh@gFVpn``YUZRA~fzP`&`jBo&`)H4QPsF-UukF!|hR=Tjts(Ew5xs*F zQvXGs({xVDXb9diHHMg!ys82PzXz218!f5=R!mHUMZS|1)|+tu(k_L;q*|liqMFoJ z=f%%xzp@K`ycr!ae?dpoPiT!erqK2idT)Fo;yp$cZCB*Ggs#{lv|f0Raw4GKtNWq= zn}T1VKKMInmn!y{MODB$DNdabCAU{`=*~T^Om3w*>Iqn{1ZOUjBh&%-DroMbbAeAju|Cc|}@2=j?_B&3ll=5#}W+X7NZ zS*O!}_v}YWl`hJDxsJ1>u(`PP0!`uU6JSJ{zY&cT=9l@-)Ad+GXY9T#u~HZI22B@t z>3V&U9BSv4w}*dyk?{O*ad_1#?5#qLNotpy2n2T;D-;ZSaz*%zqB$ z>RA-}Orb)(Bn2AIqu#%IB$G&-chz6|5&D?FqAlt(+B9Z#UOPlR&)A3WNP6JG6)y1X zpf%D&q_jaH{vyhFd^B)@NNrYz9B!O^AYpr!>zJ6zTtBH7<;teuT(rvbn39PoE;ywT z`Q>{}BhPhCUQaqRK*wB_^}*5{264x>k5np8J{hE^H`{576srLl6z*rL#*ldGvGmMl z5n&elEQ+^66{%w;b{#3qMC(3DLGVhcm%nY6ylo~OubR%kniPEfxw&YX0t{kH|f?J3_qa~ckG~#bWq=z!4)f%;rhV!qXi++bf3bD&c zxiy~OAVtd_uOp-|hltRIQRFcvrYLMMQ{*>`yAF?0;l(C41KPi=yQA zDd|a7&7e@4`{`It&yhl;cuVrIqteQi?au90Q!-l1#jYeLQlkz={K>V3@Aw}*-<$3>H*D0jhjY!V)mQ9z8#&Rlvy9e08tH5=MRPMMGpbAI{ zr`irtm~Rvnnqb?DZ0BiGuk%Q8d4dv8Qj%`-k{;mpDs}@a@S3LI4dB6wo3xMgysD;U z{Pwnu9?1?*kx0t6A#@#OzD(u=bc_k;FTFwg#T^v-&p>~TZYUSc=#Dp|>+&bGXx@{u zKQQa#54E)#lac~Zpg_TY50$|inpVv_Q>*3!p4|EweOLd22b!PIL+Y(2=m1R@KBDL9 zPo(bNqATtYr2(r%I`2vKy^*{nw=k7@Eh5u(Sb9qHJV+tBE+9`e2lhZwV$+D2b3G@C zEC*yHHplfJz63<(N!CQ*J}*$_wSilwdJy~PCZyA6CtCI+mB_V#4Y7%!a~zFC-UgHh z&Y>Y>19|S_XpZD@;C0lU+d+M}33U-BI@iylTnQY_kX$8qB2)*g(EHz^#*h77 znZzE+iU@2V%>^o672)O?y(~wQ>oO|~D(1N?kcu@Bnev$I91-9!GTcUpC|^hm)s0h~ za;y@M6>+ZO@mMZ~@%U?!^#Bs>dL&)IT?$OX9QxMKq+?7<5lhx0vwbQA&)x!e zNilP~SatA%OqgZ67*Oav30=e%YJykL5VcL@x`X!Ek7x`(94_@&TB{T&Q1DMcZMgYF zZP17Ldi4=1{Xd{9>Sxr29H2VHgx1K9XrV`S@GDdWZAoFLI%o+c{?kOp8$wP+9F{v7 zP@tml-gQ!PpX_rQZ>g77D4rf;MVo3jOkw$|7`5=~3d!_4o2+mOAxAYO4*#WIt3;xM zQUqf+tyqf&$)ED%R+=M|=71EmxW6^UaY*`Ib6t$c^&Lln#~doWwk3Cao3=?OMa_c* zoNvu>8xz%9;6JovXbovznZ@|&&jYrmd6tjK*4 zU78(Khs~l{y^Fin{kR|ZnjNyt`R< zdlO_k%%Iqloxq;px>c795^$^6bt}De4ctEU5Y52{NK^HrR=rL)f=Lv5O`-V$6ZNpZ zRK0#e`HL%1py2-uecGQ-=%Nqm+AhC`F8Tu+LibR4b{n-suEoC7Vh&U7zb-jUcHLs@ zJ~nRQu7C^*w|Taoi%#MZ;QXAz^)1}A?3Hjo{&WZOT;^nufX%eIbD+eVkFzM&g;yOr%5vLPp8FKi>_(Azx=-A;_;ntCWu;plNXpk|O~!8XJ!X-3rk_-;frz5*2iR#sV6pg_Sd6xG4&>h@@piI+S{aeOT4fozW5)2 z#GS%!&lNFUNhT%AD*)uUOd`j5nh3C8icdEzdt@Y)yj>wou+hI)706cPg&9aTuY8Nu>nS5DAFCd;*dG(w# zr`e5YYgNh+fC2>yekEuOTT`_}Zg%Imj#Ajaj0(SHBF28{HRWOx6WnzQ?^A7grGiBn zL5=uhIpQt!qFmYBrNDFMt39F0fE4>-Sr(i<2zVHPC%rf=Q0coRBwHS^Ecshb4aiCd zr+H1Tr*!;bWVso{RqHNo&t~1V>g{2j`cR{>s8vW+fdU1;PSmQ`PxM@QqfU1k94_}> zm$s+dR=r4fG$74xOnO^W9S3D~fZL}Y%TnLmubSpGfP8OKwXPE~rpjw#C0aj}@SY7< zcx07Hl}BH%pX?U@ST?@SRvGEI2C*&Fp6)||`+^J{q}V(k&UH6x`v6HY%ga|Zzzs+eRs|9MaKTx`lZlikqEY5R%}gn7?6;ktN*;b3zPA!(+?J|S$5`SJ5H+=g{nY-g5Mn~Jhr|m z@tjwcc&%s>tRLj%yUz`$+6@igv3<0Y=`dxEx44hEZ(GE$MQh!MT<2L_`nJ)W?rhje zw0^vkV*ji=%WbqST{WU*)0rz4?cZoE<`ptkpg@5F1qyzP_zyN4`RKUL%sc=9002ov JPDHLkV1myZcL)Fg literal 0 HcmV?d00001 diff --git a/application-examples/my-app/src/assets/react.svg b/application-examples/my-app/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/application-examples/my-app/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/application-examples/my-app/src/assets/vite.svg b/application-examples/my-app/src/assets/vite.svg new file mode 100644 index 00000000..5101b674 --- /dev/null +++ b/application-examples/my-app/src/assets/vite.svg @@ -0,0 +1 @@ +Vite diff --git a/application-examples/my-app/src/globals.css b/application-examples/my-app/src/globals.css new file mode 100644 index 00000000..43ce5c51 --- /dev/null +++ b/application-examples/my-app/src/globals.css @@ -0,0 +1,54 @@ +@import "tailwindcss"; + +:root { + --background: 0 0% 100%; + --foreground: 222 47% 11%; + --card: 0 0% 100%; + --card-foreground: 222 47% 11%; + --border: 214 32% 91%; + --muted-foreground: 215 16% 47%; + --primary: 221 83% 53%; + --secondary: 262 83% 58%; + --destructive: 0 84% 60%; + --radius: 0.75rem; +} + +.dark { + --background: 222 47% 11%; + --foreground: 210 40% 98%; + --card: 222 47% 15%; + --card-foreground: 210 40% 98%; + --border: 217 33% 24%; + --muted-foreground: 215 20% 65%; + --primary: 217 91% 60%; + --secondary: 262 83% 68%; + --destructive: 0 63% 60%; + --radius: 0.75rem; +} + +.my-card { + background: #1e1b4b; + border: 1px solid #4338ca; + border-radius: 10px; + padding: 18px; +} + +.my-card-title { + color: #a5b4fc; + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.my-card-value { + color: #eef2ff; + font-size: 42px; + font-weight: 800; + font-variant-numeric: tabular-nums; +} + +.my-card-label { + color: #818cf8; + font-size: 11px; +} \ No newline at end of file diff --git a/application-examples/my-app/src/index.css b/application-examples/my-app/src/index.css new file mode 100644 index 00000000..393a406c --- /dev/null +++ b/application-examples/my-app/src/index.css @@ -0,0 +1,113 @@ +@import "tailwindcss"; + +:root { + --text: #6b6375; + --text-h: #08060d; + --bg: #fff; + --border: #e5e4e7; + --code-bg: #f4f3ec; + --accent: #aa3bff; + --accent-bg: rgba(170, 59, 255, 0.1); + --accent-border: rgba(170, 59, 255, 0.5); + --social-bg: rgba(244, 243, 236, 0.5); + --shadow: + rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; + + --sans: system-ui, 'Segoe UI', Roboto, sans-serif; + --heading: system-ui, 'Segoe UI', Roboto, sans-serif; + --mono: ui-monospace, Consolas, monospace; + + font: 18px/145% var(--sans); + letter-spacing: 0.18px; + color-scheme: light dark; + color: var(--text); + background: var(--bg); + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + @media (max-width: 1024px) { + font-size: 16px; + } +} + +@media (prefers-color-scheme: dark) { + :root { + --text: #9ca3af; + --text-h: #f3f4f6; + --bg: #16171d; + --border: #2e303a; + --code-bg: #1f2028; + --accent: #c084fc; + --accent-bg: rgba(192, 132, 252, 0.15); + --accent-border: rgba(192, 132, 252, 0.5); + --social-bg: rgba(47, 48, 58, 0.5); + --shadow: + rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; + } + + #social .button-icon { + filter: invert(1) brightness(2); + } +} + +body { + margin: 0; +} + +#root { + width: 1126px; + max-width: 100%; + margin: 0 auto; + text-align: center; + border-inline: 1px solid var(--border); + min-height: 100svh; + display: flex; + flex-direction: column; + box-sizing: border-box; +} + +h1, +h2 { + font-family: var(--heading); + font-weight: 500; + color: var(--text-h); +} + +h1 { + font-size: 56px; + letter-spacing: -1.68px; + margin: 32px 0; + @media (max-width: 1024px) { + font-size: 36px; + margin: 20px 0; + } +} +h2 { + font-size: 24px; + line-height: 118%; + letter-spacing: -0.24px; + margin: 0 0 8px; + @media (max-width: 1024px) { + font-size: 20px; + } +} +p { + margin: 0; +} + +code, +.counter { + font-family: var(--mono); + display: inline-flex; + border-radius: 4px; + color: var(--text-h); +} + +code { + font-size: 15px; + line-height: 135%; + padding: 4px 8px; + background: var(--code-bg); +} diff --git a/application-examples/my-app/src/main.jsx b/application-examples/my-app/src/main.jsx new file mode 100644 index 00000000..b9a1a6de --- /dev/null +++ b/application-examples/my-app/src/main.jsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.jsx' + +createRoot(document.getElementById('root')).render( + + + , +) diff --git a/application-examples/my-app/vite.config.js b/application-examples/my-app/vite.config.js new file mode 100644 index 00000000..65fb8852 --- /dev/null +++ b/application-examples/my-app/vite.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +import react, { reactCompilerPreset } from '@vitejs/plugin-react' +import babel from '@rolldown/plugin-babel' +import tailwindcss from "@tailwindcss/vite"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + react(), + babel({ presets: [reactCompilerPreset()] }), + tailwindcss() + ], + resolve: { + dedupe: ["react", "react-dom", "@base-ui/react"], + }, + server: { + fs: { + // Allow Vite to fetch assets from the parent widget SDK directory + allow: ['..'] + } + } + +}) + diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 6377960c..290aa225 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -504,10 +504,3 @@ export default function App() { ); } -{ - /* -//create react app -//link public-widget-sdk -//npm run dev -//send this file tp yash to copy paste */ -} From cb5d9e9f7df062854751d3848fff6b769f75eac9 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Tue, 28 Jul 2026 10:33:13 +0530 Subject: [PATCH 53/66] updated application example name --- examples/application-example.js | 183 ------------------ .../application-example}/.env.example | 0 .../application-example}/.gitignore | 0 .../application-example}/README.md | 0 .../application-example}/eslint.config.js | 0 .../application-example}/index.html | 0 .../application-example}/package-lock.json | 0 .../application-example}/package.json | 0 .../application-example}/public/favicon.svg | 0 .../application-example}/public/icons.svg | 0 .../application-example}/src/App.css | 0 .../application-example}/src/App.jsx | 0 .../application-example}/src/Test.tsx | 0 .../application-example}/src/assets/hero.png | Bin .../application-example}/src/assets/react.svg | 0 .../application-example}/src/assets/vite.svg | 0 .../application-example}/src/globals.css | 0 .../application-example}/src/index.css | 0 .../application-example}/src/main.jsx | 0 .../application-example}/vite.config.js | 0 20 files changed, 183 deletions(-) delete mode 100644 examples/application-example.js rename {application-examples/my-app => examples/application-example}/.env.example (100%) rename {application-examples/my-app => examples/application-example}/.gitignore (100%) rename {application-examples/my-app => examples/application-example}/README.md (100%) rename {application-examples/my-app => examples/application-example}/eslint.config.js (100%) rename {application-examples/my-app => examples/application-example}/index.html (100%) rename {application-examples/my-app => examples/application-example}/package-lock.json (100%) rename {application-examples/my-app => examples/application-example}/package.json (100%) rename {application-examples/my-app => examples/application-example}/public/favicon.svg (100%) rename {application-examples/my-app => examples/application-example}/public/icons.svg (100%) rename {application-examples/my-app => examples/application-example}/src/App.css (100%) rename {application-examples/my-app => examples/application-example}/src/App.jsx (100%) rename {application-examples/my-app => examples/application-example}/src/Test.tsx (100%) rename {application-examples/my-app => examples/application-example}/src/assets/hero.png (100%) rename {application-examples/my-app => examples/application-example}/src/assets/react.svg (100%) rename {application-examples/my-app => examples/application-example}/src/assets/vite.svg (100%) rename {application-examples/my-app => examples/application-example}/src/globals.css (100%) rename {application-examples/my-app => examples/application-example}/src/index.css (100%) rename {application-examples/my-app => examples/application-example}/src/main.jsx (100%) rename {application-examples/my-app => examples/application-example}/vite.config.js (100%) diff --git a/examples/application-example.js b/examples/application-example.js deleted file mode 100644 index e750d6bc..00000000 --- a/examples/application-example.js +++ /dev/null @@ -1,183 +0,0 @@ -import React from "react"; -import { - LatestDataComponent, - anedyaClientInit, - ChartWidget, - LatestDataGauge, -} from "public-sdk"; - -function App() { -const tokenId = "itATCNCVamYNmwfdeBumQMwS"; -const token = "Evd8wL35Xt4tNQOXP11YddiRHtM74jqw3JZYuIaPmnWxNozbmnNTUfVaqXmQERV1"; -const nodeId = "20deeee8-f8ae-11ee-9dd8-c3aa61afe2fb"; - const client = anedyaClientInit(tokenId, token); - - const currentTime = Date.now(); // ms timestamp - const twentyFourHoursAgo = currentTime - 86400 * 1000; // ms timestamp - - return ( -
-

Test Widget SDK

-
-
- d.toLocaleDateString()} - yTickFormat={(v) => `${v} Β°C`} - tooltipFormat={(d, unit) => - `${new Date(d.timestamp * 1000)} : ${d.value} Celsius` - } - onStyleChange={(data) => { - return { - title: { color: "red" }, - container: { - background: "rgba(232, 236, 240, 1)", - borderRadius: 10, - }, - }; - }} - /> -
- -
- { - return { - text: `${value}`, - unitText: unit, - position: "right", // "left" | "right" | "top" | "bottom" - unitStyle: "subscript", // "normal" | "subscript" | "superscript" - }; - }} - onStyleChange={(value) => { - if (value > 80) { - return { - value: { color: "black" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -
- -
- { - if (value > 80) { - return { - value: { color: "red" }, - label: { color: "orange" }, - }; - } - - return {}; // keep original styling - }} - /> -
-
-
- ); -} - -export default App; - diff --git a/application-examples/my-app/.env.example b/examples/application-example/.env.example similarity index 100% rename from application-examples/my-app/.env.example rename to examples/application-example/.env.example diff --git a/application-examples/my-app/.gitignore b/examples/application-example/.gitignore similarity index 100% rename from application-examples/my-app/.gitignore rename to examples/application-example/.gitignore diff --git a/application-examples/my-app/README.md b/examples/application-example/README.md similarity index 100% rename from application-examples/my-app/README.md rename to examples/application-example/README.md diff --git a/application-examples/my-app/eslint.config.js b/examples/application-example/eslint.config.js similarity index 100% rename from application-examples/my-app/eslint.config.js rename to examples/application-example/eslint.config.js diff --git a/application-examples/my-app/index.html b/examples/application-example/index.html similarity index 100% rename from application-examples/my-app/index.html rename to examples/application-example/index.html diff --git a/application-examples/my-app/package-lock.json b/examples/application-example/package-lock.json similarity index 100% rename from application-examples/my-app/package-lock.json rename to examples/application-example/package-lock.json diff --git a/application-examples/my-app/package.json b/examples/application-example/package.json similarity index 100% rename from application-examples/my-app/package.json rename to examples/application-example/package.json diff --git a/application-examples/my-app/public/favicon.svg b/examples/application-example/public/favicon.svg similarity index 100% rename from application-examples/my-app/public/favicon.svg rename to examples/application-example/public/favicon.svg diff --git a/application-examples/my-app/public/icons.svg b/examples/application-example/public/icons.svg similarity index 100% rename from application-examples/my-app/public/icons.svg rename to examples/application-example/public/icons.svg diff --git a/application-examples/my-app/src/App.css b/examples/application-example/src/App.css similarity index 100% rename from application-examples/my-app/src/App.css rename to examples/application-example/src/App.css diff --git a/application-examples/my-app/src/App.jsx b/examples/application-example/src/App.jsx similarity index 100% rename from application-examples/my-app/src/App.jsx rename to examples/application-example/src/App.jsx diff --git a/application-examples/my-app/src/Test.tsx b/examples/application-example/src/Test.tsx similarity index 100% rename from application-examples/my-app/src/Test.tsx rename to examples/application-example/src/Test.tsx diff --git a/application-examples/my-app/src/assets/hero.png b/examples/application-example/src/assets/hero.png similarity index 100% rename from application-examples/my-app/src/assets/hero.png rename to examples/application-example/src/assets/hero.png diff --git a/application-examples/my-app/src/assets/react.svg b/examples/application-example/src/assets/react.svg similarity index 100% rename from application-examples/my-app/src/assets/react.svg rename to examples/application-example/src/assets/react.svg diff --git a/application-examples/my-app/src/assets/vite.svg b/examples/application-example/src/assets/vite.svg similarity index 100% rename from application-examples/my-app/src/assets/vite.svg rename to examples/application-example/src/assets/vite.svg diff --git a/application-examples/my-app/src/globals.css b/examples/application-example/src/globals.css similarity index 100% rename from application-examples/my-app/src/globals.css rename to examples/application-example/src/globals.css diff --git a/application-examples/my-app/src/index.css b/examples/application-example/src/index.css similarity index 100% rename from application-examples/my-app/src/index.css rename to examples/application-example/src/index.css diff --git a/application-examples/my-app/src/main.jsx b/examples/application-example/src/main.jsx similarity index 100% rename from application-examples/my-app/src/main.jsx rename to examples/application-example/src/main.jsx diff --git a/application-examples/my-app/vite.config.js b/examples/application-example/vite.config.js similarity index 100% rename from application-examples/my-app/vite.config.js rename to examples/application-example/vite.config.js From 70ea34470bd06bb440bfc5cfa9afeaf894070a65 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Tue, 28 Jul 2026 12:10:30 +0530 Subject: [PATCH 54/66] Stop tracking test folder --- test/my-app/.env.example | 3 - test/my-app/.gitignore | 25 - test/my-app/README.md | 18 - test/my-app/eslint.config.js | 29 - test/my-app/index.html | 13 - test/my-app/package-lock.json | 4281 ------------------------------ test/my-app/package.json | 36 - test/my-app/public/favicon.svg | 1 - test/my-app/public/icons.svg | 24 - test/my-app/src/App.css | 184 -- test/my-app/src/App.jsx | 506 ---- test/my-app/src/Test.tsx | 1335 ---------- test/my-app/src/assets/hero.png | Bin 44919 -> 0 bytes test/my-app/src/assets/react.svg | 1 - test/my-app/src/assets/vite.svg | 1 - test/my-app/src/globals.css | 54 - test/my-app/src/index.css | 113 - test/my-app/src/main.jsx | 10 - test/my-app/vite.config.js | 24 - 19 files changed, 6658 deletions(-) delete mode 100644 test/my-app/.env.example delete mode 100644 test/my-app/.gitignore delete mode 100644 test/my-app/README.md delete mode 100644 test/my-app/eslint.config.js delete mode 100644 test/my-app/index.html delete mode 100644 test/my-app/package-lock.json delete mode 100644 test/my-app/package.json delete mode 100644 test/my-app/public/favicon.svg delete mode 100644 test/my-app/public/icons.svg delete mode 100644 test/my-app/src/App.css delete mode 100644 test/my-app/src/App.jsx delete mode 100644 test/my-app/src/Test.tsx delete mode 100644 test/my-app/src/assets/hero.png delete mode 100644 test/my-app/src/assets/react.svg delete mode 100644 test/my-app/src/assets/vite.svg delete mode 100644 test/my-app/src/globals.css delete mode 100644 test/my-app/src/index.css delete mode 100644 test/my-app/src/main.jsx delete mode 100644 test/my-app/vite.config.js diff --git a/test/my-app/.env.example b/test/my-app/.env.example deleted file mode 100644 index ec1a2dc6..00000000 --- a/test/my-app/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -VITE_CARD_WIDGET_TOKEN_ID="your_token_id_here" -VITE_CARD_WIDGET_TOKEN="your_token_secret_here" -VITE_CARD_WIDGET_NODE_ID="your_node_id_here" \ No newline at end of file diff --git a/test/my-app/.gitignore b/test/my-app/.gitignore deleted file mode 100644 index 7ceb59f8..00000000 --- a/test/my-app/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -.env diff --git a/test/my-app/README.md b/test/my-app/README.md deleted file mode 100644 index e16d995e..00000000 --- a/test/my-app/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# React + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) - -## React Compiler - -The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. - -Note: This will impact Vite dev & build performances. - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/test/my-app/eslint.config.js b/test/my-app/eslint.config.js deleted file mode 100644 index 4fa125da..00000000 --- a/test/my-app/eslint.config.js +++ /dev/null @@ -1,29 +0,0 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' -import { defineConfig, globalIgnores } from 'eslint/config' - -export default defineConfig([ - globalIgnores(['dist']), - { - files: ['**/*.{js,jsx}'], - extends: [ - js.configs.recommended, - reactHooks.configs.flat.recommended, - reactRefresh.configs.vite, - ], - languageOptions: { - ecmaVersion: 2020, - globals: globals.browser, - parserOptions: { - ecmaVersion: 'latest', - ecmaFeatures: { jsx: true }, - sourceType: 'module', - }, - }, - rules: { - 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], - }, - }, -]) diff --git a/test/my-app/index.html b/test/my-app/index.html deleted file mode 100644 index 53beb493..00000000 --- a/test/my-app/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - my-app - - -
- - - diff --git a/test/my-app/package-lock.json b/test/my-app/package-lock.json deleted file mode 100644 index 53d391c0..00000000 --- a/test/my-app/package-lock.json +++ /dev/null @@ -1,4281 +0,0 @@ -{ - "name": "my-app", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "my-app", - "version": "0.0.0", - "dependencies": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.1", - "@mui/material": "^9.2.0", - "public-widget-sdk": "file:../../", - "react": "^19.2.4", - "react-dom": "^19.2.4" - }, - "devDependencies": { - "@babel/core": "^7.29.0", - "@eslint/js": "^9.39.4", - "@rolldown/plugin-babel": "^0.2.1", - "@tailwindcss/vite": "^4.3.3", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "babel-plugin-react-compiler": "^1.0.0", - "eslint": "^9.39.4", - "eslint-plugin-react-hooks": "^7.0.1", - "eslint-plugin-react-refresh": "^0.5.2", - "globals": "^17.4.0", - "tailwindcss": "^4.3.3", - "vite": "^8.0.1" - } - }, - "../..": { - "name": "public-widget-sdk", - "version": "5.5.0", - "license": "ISC", - "dependencies": { - "@anedyasystems/anedya-frontend-sdk": "^0.1.1", - "@types/d3": "^7.4.3", - "clsx": "^2.1.1", - "d3": "^7.9.0", - "tailwind-merge": "^3.6.0" - }, - "devDependencies": { - "@base-ui/react": "^1.6.0", - "@tailwindcss/cli": "^4.3.3", - "@types/react": "^19.2.17", - "@types/react-dom": "^19.2.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tailwindcss": "^4.3.2", - "tsdown": "^0.22.13", - "typescript": "^5.7.3" - }, - "peerDependencies": { - "@base-ui/react": "^1.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emotion/babel-plugin": { - "version": "11.13.5", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", - "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/serialize": "^1.3.3", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "license": "MIT" - }, - "node_modules/@emotion/cache": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", - "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", - "license": "MIT", - "dependencies": { - "@emotion/memoize": "^0.9.0", - "@emotion/sheet": "^1.4.0", - "@emotion/utils": "^1.4.2", - "@emotion/weak-memoize": "^0.4.0", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", - "license": "MIT" - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", - "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", - "license": "MIT", - "dependencies": { - "@emotion/memoize": "^0.9.0" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", - "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", - "license": "MIT" - }, - "node_modules/@emotion/react": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", - "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.13.5", - "@emotion/cache": "^11.14.0", - "@emotion/serialize": "^1.3.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", - "@emotion/utils": "^1.4.2", - "@emotion/weak-memoize": "^0.4.0", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", - "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", - "license": "MIT", - "dependencies": { - "@emotion/hash": "^0.9.2", - "@emotion/memoize": "^0.9.0", - "@emotion/unitless": "^0.10.0", - "@emotion/utils": "^1.4.2", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", - "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", - "license": "MIT" - }, - "node_modules/@emotion/styled": { - "version": "11.14.1", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", - "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.13.5", - "@emotion/is-prop-valid": "^1.3.0", - "@emotion/serialize": "^1.3.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", - "@emotion/utils": "^1.4.2" - }, - "peerDependencies": { - "@emotion/react": "^11.0.0-rc.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/unitless": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", - "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", - "license": "MIT" - }, - "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", - "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@emotion/utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", - "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", - "license": "MIT" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", - "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", - "license": "MIT" - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", - "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.6.tgz", - "integrity": "sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.3.0", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@mui/core-downloads-tracker": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-9.2.0.tgz", - "integrity": "sha512-+XMav+ZaXkZKUFUgzjrfMEedfyJKxxviAske2q8N8CWDMeqZdDU2lWMkiUPiB388hGaDqhwvOAwkrsc/pUyp8g==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - } - }, - "node_modules/@mui/material": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.2.0.tgz", - "integrity": "sha512-+YTRSgGKGrrRo2XJZXs7JRA6qHoHWvNtxyqxnrRJTBmIuLOUpxxh7m4G9lF4tWberxGFY+EqkkRPgJCl+fSMJg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2", - "@mui/core-downloads-tracker": "^9.2.0", - "@mui/system": "^9.2.0", - "@mui/types": "^9.1.1", - "@mui/utils": "^9.2.0", - "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.12", - "clsx": "^2.1.1", - "csstype": "^3.2.3", - "prop-types": "^15.8.1", - "react-is": "^19.2.6", - "react-transition-group": "^4.4.5" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^9.2.0", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@mui/material-pigment-css": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-9.2.0.tgz", - "integrity": "sha512-w9wpyDxGPGnAACPB2hKhCDmILJIAvQxrfjUbIAEa0AznX1rOjaz5N+yB1uuw8ixnJcpEh/tPbD9oEe19wcWPHw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2", - "@mui/utils": "^9.2.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/styled-engine": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-9.1.1.tgz", - "integrity": "sha512-neaYKdJfvEG54q8efHLJR7swpHG/gfSv9xGqW5iTSMsubD7yPCPFrhVBt284j1DOF3uZaaDJSHQL7gz6jGF21Q==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2", - "@emotion/cache": "^11.14.0", - "@emotion/serialize": "^1.3.3", - "@emotion/sheet": "^1.4.0", - "csstype": "^3.2.3", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } - } - }, - "node_modules/@mui/system": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-9.2.0.tgz", - "integrity": "sha512-YvUJwKoGVtbnOm2PyPi5TvX2d1rOA6sqSpEWVs4WmXNIaFTuYmNUaVdU2o1NKUEe31URnD3E8ZVUMcsLQXwcYg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2", - "@mui/private-theming": "^9.2.0", - "@mui/styled-engine": "^9.1.1", - "@mui/types": "^9.1.1", - "@mui/utils": "^9.2.0", - "clsx": "^2.1.1", - "csstype": "^3.2.3", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/types": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.1.1.tgz", - "integrity": "sha512-Zjt7u8wNvDg40rPTGoL+TnfkpuSKjwubsNSFRH1KAVZLcaV4I3AFNHIFbvH7p4F3alEibSbdd90xAgn5Rnfndg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/utils": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.2.0.tgz", - "integrity": "sha512-OsUH5zhlSOM4xmLl53+agug1M1UyWb4zxFxWQCqwKTKUeQPvTENtg3JhrroBD2qpCLKsX5W/DYGERJ4mBUbc8g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.29.2", - "@mui/types": "^9.1.1", - "@types/prop-types": "^15.7.15", - "clsx": "^2.1.1", - "prop-types": "^15.8.1", - "react-is": "^19.2.6" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", - "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.140.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", - "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.0.tgz", - "integrity": "sha512-9yB1l95IrJuNGDFdOYe79vdApdz6WWBCObE+rQ2LUliYUlcyFwSYIb2xb5/Ifw7dAtMy2ZqNyd8QTSOc7duAKw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0.tgz", - "integrity": "sha512-pexNaW9ACLUOaBITOpU6qVu4VrsOFIjTv6bzgu0YUATo4eUJx0V605PxwZfndpPOn0ilqGqvGQ0M8UW0IE24jg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.0.tgz", - "integrity": "sha512-NqKYaq0355ZmNMG4QGpxtEDxsc7tGDhjhCm4PpE0cwnBW+5Il95LJyq414niEiaKLVjnVHBEjSo1wngKxJNiFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.0.tgz", - "integrity": "sha512-3vPoHzh6eBTz9IbB0/qZdSr0Qeks2echn+I4cHu2joV74VriPDdldswksEDzrl1mBB+oPRi+67+3Ib59paxIPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.0.tgz", - "integrity": "sha512-E6NNefZ1bUVmKJq2tJkf45J4Zyczj7qm9rUT7NY+Xo2474Y13qWAwc2tvBt0BAVbmtXR1llkxXg0Ou1jbDf2SQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.0.tgz", - "integrity": "sha512-D+TgkdgM1vu+7/Fpf8+v0ARW+RXEP9Ccazgm8zQ4JFFd9Q7SrYQ2TakU5S5ihazQDgpKyAgZDOcIFsvoHmTZ8w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.0.tgz", - "integrity": "sha512-wUqdwJBbAv0APN87GecstdMUtLjjNTs0hBALpxETD73mccFxdmt/XeizXDtN5RAlBwNKmI+Tg+blect2G+8IeQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.0.tgz", - "integrity": "sha512-9DtF35qR9/NrfhM4oxLplCzVVjE+KKm8Pjemi0i/sdhAWkUasjmSo8WTTubNJClhSHCfyk2yeyoXDQEDPtDAAw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.0.tgz", - "integrity": "sha512-RzuHrBh8X8Hntd2N4VR02QGEciq/9JhcZoTpR/Cee6otRrlILGCf3cg2ygHuih+ZebUnWmMrDX6ITI85btO6rQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.0.tgz", - "integrity": "sha512-MK7L0018jjh1jR3mh21G2j1zAVcpscJBlPo2z19pRjv2XOYGRhaV4LyiD8HO6nCDdZln9IFgCMIV5yt4E3klGQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.0.tgz", - "integrity": "sha512-gyrxLQ9NfGb/9LoVnC4kb9miUghw1mghnkfYvNHSnVIXriabnfgGPUP4RLcJm87q3KgYz4FYUG8IDiWUT+CpSw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.0.tgz", - "integrity": "sha512-/6VFMQGRmrhP77KXDC+StIxGzcNp5JOIyYtw0CQ8gPlzhpiIRucYfoM5FaFamHd5BJYIdH86yfP46l1p3WdrFA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.0.tgz", - "integrity": "sha512-rwdbUL465kisF24WEJLvP3JrEG6E5GRuIHt5wpMwHGERtHe4Wm2CIvtf5gTBgr2tGOHKh5NdKEAFS2VkOPE91g==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.2", - "@emnapi/runtime": "1.11.2", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", - "integrity": "sha512-+5suHwRiKGmhwyUaNT8a5QbrBvLFh2DbO910TEmGRH1aSxwrCezodvGQnulv4uiWEIv1Kq4ypRsJ5+O+ry1DiA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.0.tgz", - "integrity": "sha512-WfFv6/qGufotqBSBzBYwgpCkJBk8Nj7697LL9vTz/XWc67e0r3oewu8iMRwQj3AUL45GVD7wVsPjCsAAtW66Wg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/plugin-babel": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@rolldown/plugin-babel/-/plugin-babel-0.2.3.tgz", - "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=22.12.0 || ^24.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.29.0 || ^8.0.0-rc.1", - "@babel/plugin-transform-runtime": "^7.29.0 || ^8.0.0-rc.1", - "@babel/runtime": "^7.27.0 || ^8.0.0-rc.1", - "rolldown": "^1.0.0-rc.5", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@babel/plugin-transform-runtime": { - "optional": true - }, - "@babel/runtime": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tailwindcss/node": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", - "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.24.1", - "jiti": "^2.7.0", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.3.3" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/node/node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", - "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.3", - "@tailwindcss/oxide-darwin-arm64": "4.3.3", - "@tailwindcss/oxide-darwin-x64": "4.3.3", - "@tailwindcss/oxide-freebsd-x64": "4.3.3", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", - "@tailwindcss/oxide-linux-x64-musl": "4.3.3", - "@tailwindcss/oxide-wasm32-wasi": "4.3.3", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", - "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", - "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", - "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", - "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", - "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", - "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", - "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", - "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", - "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", - "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.11.1", - "@emnapi/runtime": "^1.11.1", - "@emnapi/wasi-threads": "^1.2.2", - "@napi-rs/wasm-runtime": "^1.1.4", - "@tybys/wasm-util": "^0.10.2", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", - "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", - "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz", - "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.3.3", - "@tailwindcss/oxide": "4.3.3", - "tailwindcss": "4.3.3" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7 || ^8" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", - "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@types/react-transition-group": { - "version": "4.4.12", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", - "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.4.tgz", - "integrity": "sha512-XcCQz0TBpBgljhj0gMuuDj49i6Ytqh5q1osT/Gp5uAVJUCTWxyskk/l1jwYYiu2xcNHHipdMz40EGfM1VdamVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.1" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } - } - }, - "node_modules/acorn": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz", - "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-react-compiler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", - "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/types": "^7.26.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.1.tgz", - "integrity": "sha512-HYXq73DDpCtNzOmrFsm9eSwCvWCql0RzqjpDzXN9EadiLJ4DNat0nsZ/Bzmy+Ud12mb4/zKDY0cQ805ZzN+i0A==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", - "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.28.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", - "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "baseline-browser-mapping": "^2.10.44", - "caniuse-lite": "^1.0.30001806", - "electron-to-chromium": "^1.5.393", - "node-releases": "^2.0.51", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001806", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", - "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "license": "MIT", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cosmiconfig/node_modules/yaml": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.395", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", - "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", - "dev": true, - "license": "ISC" - }, - "node_modules/enhanced-resolve": { - "version": "5.24.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz", - "integrity": "sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.6", - "@eslint/js": "9.39.5", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.14.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", - "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "hermes-parser": "^0.25.1", - "zod": "^3.25.0 || ^4.0.0", - "zod-validation-error": "^3.5.0 || ^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" - } - }, - "node_modules/eslint-plugin-react-refresh": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.3.tgz", - "integrity": "sha512-5EMmLCV98Pi4o/f/3DP/v/tNqLHMIc9I8LKClNDWhZ9JTho89/kQcitCXQBMG7sAfVRK0Ie3T2EDOzp1YXYiVA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "eslint": "^9 || ^10" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", - "license": "MIT" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.3.tgz", - "integrity": "sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", - "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hermes-estree": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", - "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hermes-estree": "0.25.1" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.51", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", - "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/postcss": { - "version": "8.5.22", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.22.tgz", - "integrity": "sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.16", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/public-widget-sdk": { - "resolved": "../..", - "link": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/react": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", - "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", - "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.8" - } - }, - "node_modules/react-is": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", - "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", - "license": "MIT" - }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "license": "BSD-3-Clause", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/rolldown": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.0.tgz", - "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@oxc-project/types": "=0.140.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.2.0", - "@rolldown/binding-darwin-arm64": "1.2.0", - "@rolldown/binding-darwin-x64": "1.2.0", - "@rolldown/binding-freebsd-x64": "1.2.0", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.0", - "@rolldown/binding-linux-arm64-gnu": "1.2.0", - "@rolldown/binding-linux-arm64-musl": "1.2.0", - "@rolldown/binding-linux-ppc64-gnu": "1.2.0", - "@rolldown/binding-linux-s390x-gnu": "1.2.0", - "@rolldown/binding-linux-x64-gnu": "1.2.0", - "@rolldown/binding-linux-x64-musl": "1.2.0", - "@rolldown/binding-openharmony-arm64": "1.2.0", - "@rolldown/binding-wasm32-wasi": "1.2.0", - "@rolldown/binding-win32-arm64-msvc": "1.2.0", - "@rolldown/binding-win32-x64-msvc": "1.2.0" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", - "license": "MIT" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", - "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", - "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD", - "optional": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz", - "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "lightningcss": "^1.32.0", - "picomatch": "^4.0.5", - "postcss": "^8.5.17", - "rolldown": "~1.1.5", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.3.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/vite/node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/vite/node_modules/@oxc-project/types": { - "version": "0.139.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", - "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", - "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", - "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", - "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", - "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", - "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", - "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", - "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", - "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", - "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", - "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", - "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", - "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", - "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.11.1", - "@emnapi/runtime": "1.11.1", - "@napi-rs/wasm-runtime": "^1.1.6" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", - "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", - "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/vite/node_modules/rolldown": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", - "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.139.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.1.5", - "@rolldown/binding-darwin-arm64": "1.1.5", - "@rolldown/binding-darwin-x64": "1.1.5", - "@rolldown/binding-freebsd-x64": "1.1.5", - "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", - "@rolldown/binding-linux-arm64-gnu": "1.1.5", - "@rolldown/binding-linux-arm64-musl": "1.1.5", - "@rolldown/binding-linux-ppc64-gnu": "1.1.5", - "@rolldown/binding-linux-s390x-gnu": "1.1.5", - "@rolldown/binding-linux-x64-gnu": "1.1.5", - "@rolldown/binding-linux-x64-musl": "1.1.5", - "@rolldown/binding-openharmony-arm64": "1.1.5", - "@rolldown/binding-wasm32-wasi": "1.1.5", - "@rolldown/binding-win32-arm64-msvc": "1.1.5", - "@rolldown/binding-win32-x64-msvc": "1.1.5" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "dev": true, - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-validation-error": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", - "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } - } - } -} diff --git a/test/my-app/package.json b/test/my-app/package.json deleted file mode 100644 index 69feefbc..00000000 --- a/test/my-app/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "my-app", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "lint": "eslint .", - "preview": "vite preview" - }, - "dependencies": { - "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.1", - "@mui/material": "^9.2.0", - "public-widget-sdk": "file:../../", - "react": "^19.2.4", - "react-dom": "^19.2.4" - }, - "devDependencies": { - "@babel/core": "^7.29.0", - "@eslint/js": "^9.39.4", - "@rolldown/plugin-babel": "^0.2.1", - "@tailwindcss/vite": "^4.3.3", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "babel-plugin-react-compiler": "^1.0.0", - "eslint": "^9.39.4", - "eslint-plugin-react-hooks": "^7.0.1", - "eslint-plugin-react-refresh": "^0.5.2", - "globals": "^17.4.0", - "tailwindcss": "^4.3.3", - "vite": "^8.0.1" - } -} diff --git a/test/my-app/public/favicon.svg b/test/my-app/public/favicon.svg deleted file mode 100644 index 6893eb13..00000000 --- a/test/my-app/public/favicon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/test/my-app/public/icons.svg b/test/my-app/public/icons.svg deleted file mode 100644 index e9522193..00000000 --- a/test/my-app/public/icons.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/my-app/src/App.css b/test/my-app/src/App.css deleted file mode 100644 index f90339d8..00000000 --- a/test/my-app/src/App.css +++ /dev/null @@ -1,184 +0,0 @@ -.counter { - font-size: 16px; - padding: 5px 10px; - border-radius: 5px; - color: var(--accent); - background: var(--accent-bg); - border: 2px solid transparent; - transition: border-color 0.3s; - margin-bottom: 24px; - - &:hover { - border-color: var(--accent-border); - } - &:focus-visible { - outline: 2px solid var(--accent); - outline-offset: 2px; - } -} - -.hero { - position: relative; - - .base, - .framework, - .vite { - inset-inline: 0; - margin: 0 auto; - } - - .base { - width: 170px; - position: relative; - z-index: 0; - } - - .framework, - .vite { - position: absolute; - } - - .framework { - z-index: 1; - top: 34px; - height: 28px; - transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg) - scale(1.4); - } - - .vite { - z-index: 0; - top: 107px; - height: 26px; - width: auto; - transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg) - scale(0.8); - } -} - -#center { - display: flex; - flex-direction: column; - gap: 25px; - place-content: center; - place-items: center; - flex-grow: 1; - - @media (max-width: 1024px) { - padding: 32px 20px 24px; - gap: 18px; - } -} - -#next-steps { - display: flex; - border-top: 1px solid var(--border); - text-align: left; - - & > div { - flex: 1 1 0; - padding: 32px; - @media (max-width: 1024px) { - padding: 24px 20px; - } - } - - .icon { - margin-bottom: 16px; - width: 22px; - height: 22px; - } - - @media (max-width: 1024px) { - flex-direction: column; - text-align: center; - } -} - -#docs { - border-right: 1px solid var(--border); - - @media (max-width: 1024px) { - border-right: none; - border-bottom: 1px solid var(--border); - } -} - -#next-steps ul { - list-style: none; - padding: 0; - display: flex; - gap: 8px; - margin: 32px 0 0; - - .logo { - height: 18px; - } - - a { - color: var(--text-h); - font-size: 16px; - border-radius: 6px; - background: var(--social-bg); - display: flex; - padding: 6px 12px; - align-items: center; - gap: 8px; - text-decoration: none; - transition: box-shadow 0.3s; - - &:hover { - box-shadow: var(--shadow); - } - .button-icon { - height: 18px; - width: 18px; - } - } - - @media (max-width: 1024px) { - margin-top: 20px; - flex-wrap: wrap; - justify-content: center; - - li { - flex: 1 1 calc(50% - 8px); - } - - a { - width: 100%; - justify-content: center; - box-sizing: border-box; - } - } -} - -#spacer { - height: 88px; - border-top: 1px solid var(--border); - @media (max-width: 1024px) { - height: 48px; - } -} - -.ticks { - position: relative; - width: 100%; - - &::before, - &::after { - content: ''; - position: absolute; - top: -4.5px; - border: 5px solid transparent; - } - - &::before { - left: 0; - border-left-color: var(--border); - } - &::after { - right: 0; - border-right-color: var(--border); - } -} diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx deleted file mode 100644 index 290aa225..00000000 --- a/test/my-app/src/App.jsx +++ /dev/null @@ -1,506 +0,0 @@ -import React from "react"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "../../../src"; -import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "public-widget-sdk/styles.css"; -import { relativeTime } from "public-widget-sdk/formatters"; -import "./index.css"; -// This demo has its own Tailwind build (see vite.config.js + src/index.css), -// specifically to test consumer-side class overrides via `className`/`styles`. -// A real consumer app needs the same setup β€” the widget package's own -// precompiled stylesheet only covers its built-in default classes, not -// arbitrary classes a consumer passes in. - -const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; -const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; -const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; - -const anedya = new Anedya(); -const config = anedya.newConfig(tokenId, token); -const client = anedya.newClient(config); -const node = anedya.newNode(client, nodeId); - -/** - * A reusable theme, shareable across every CardWidget instance in your - * app. Only specify the slots you actually want to change from the - * built-in default β€” anything omitted falls back to lightTheme/darkTheme. - */ -const emeraldTheme = { - styles: { - container: "bg-emerald-50 border-emerald-200", - title: "text-emerald-700", - value: "text-emerald-900", - label: "text-emerald-500", - }, -}; - -export const gaugeCustomLightTheme = { - styles: { - // Tailwind classes for HTML container and text wrappers - container: "bg-emerald-50 border-emerald-200", - title: "text-emerald-800", - value: "text-emerald-950", - label: "text-emerald-600", - - // Hex colors for D3 SVG elements - track: "#E2E8F0", // Soft gray background arc (slate-200) - bar: "#10B981", // Primary value fill (emerald-500) - needle: "#047857", // Darker accent needle for high visibility (emerald-700) - needleCap: "#065F46", // Needle center cap (emerald-800) - }, -}; - -export const gaugeCustomDarkTheme = { - styles: { - // Tailwind classes for HTML container and text wrappers - container: "bg-yellow-500 border-emerald-800/50 backdrop-blur-sm", - title: "text-red-500", - value: "text-yellow-500", - label: "text-red-500", - - // Hex colors for D3 SVG elements - track: "text-red-500", // Dark muted background arc (slate-800) - bar: "text-yellow-500", // High-contrast bright fill (emerald-400) - needle: "text-red-500", // Bright needle for dark mode contrast (emerald-300) - needleCap: "text-yellow-500", // Bright needle center cap (emerald-200) - }, -}; - -const commonProps = { node, variable: "humidity" }; - -export default function App() { - return ( -
- {/* ============================================================ - * 1. Default appearance β€” no theme, no styles, no - * formatting props. Every fallback in the widget in one place. - * ============================================================ */} - { - if (meta.kind === "error") { - return { - renderError: () => ( - - Sensor unreachable - - ), - }; - } - if (meta.kind === "empty") { - return { - renderEmpty: () => ( - β€” no reading yet β€” - ), - }; - } - }} - /> - - {/* ============================================================ - * 2. theme β€” a reusable, shareable WidgetTheme object. Same - * effect across every widget instance that uses it. - * ============================================================ */} - - {/* Built-in preset names also work directly: */} - - {/* ============================================================ - * 3. styles vs className β€” THE distinction to understand: - * - * - `styles` (plural, an OBJECT): per-SLOT overrides. - * Keys are "container" | "title" | "value" | "unit" | "label" - * β€” lets you reach INSIDE the widget and style individual - * pieces independently. - * - * - `className` (singular, a STRING): the ordinary React - * convention β€” one class applied ONLY to the widget's - * outermost container element, same as you'd pass to any - * other component. It's merged (via twMerge) with whatever - * styles.container already resolved to, not a - * replacement for it. - * - * This example uses BOTH at once so the difference is visible: - * className adds a shadow to the outer box, styles.value/ - * styles.title style two INNER pieces independently. - * ============================================================ */} - - {/* ============================================================ - * 4. Plain CSS classes β€” styles works with ANY class source, - * not just Tailwind. These reference plain hand-written CSS - * classes (e.g. defined in a .css file this app already imports). - * ============================================================ */} - {/* */} - {/* ============================================================ - * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` - * work exactly as they do anywhere else in your app, because - * styles just forwards whatever string you write straight - * to `className`. This widget does NOT have its own custom - * breakpoint system β€” these prefixes are compiled by YOUR - * project's Tailwind config and respond to the BROWSER VIEWPORT, - * same as native Tailwind everywhere else. If your own - * tailwind.config.js customizes `theme.screens`, these prefixes - * automatically follow that customization too β€” nothing to - * configure on the widget's side. - * ============================================================ */} - {/* */} - {/* ============================================================ - * 6. formatValue / labelText β€” simple formatting hooks, distinct - * from styling. formatValue controls the displayed number's - * text; labelText controls the caption under it. - * ============================================================ */} - {/* `${v.toFixed(2)} % RH`} - labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - - /> */} - {/* ============================================================ - * 7. onStyleChange β€” conditional class overrides driven by the - * RAW fetched data ({ value, timestamp }), always applied on top - * of everything else (theme, styles, className). - * ============================================================ */} - {/* { - if (!data) return; - - if (data.value > 80) { - return { - title: "High Humidity", - theme: "dark", - styles: { - value: "text-red-500" - } - }; - } - - return { - title: "Humidity", - theme: "light" - }; - }} - - /> */} - {/* ============================================================ - * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, - * applied as inline styles on the container, independent of the - * whole styles/theme system. - * ============================================================ */} - {/* */} - - { - if (!data) return {}; - const { value } = data; - if (value > 60) return { title: "πŸ”΄ Critical", color: "#dc2626" }; - if (value > 50) return { title: "🟑 Warning", color: "#f59e0b" }; - return { title: "🟒 Normal", color: "#10b981" }; - }} - // styles={{ - // container:"", - // // "bg-slate-50 dark:bg-slate-800 rounded-2xl shadow-lg border", - // title: "text-base font-bold tracking-wide", - // value: "text-[100px]", - // unit: "text-[200px] opacity-75", - // label: "text-xs italic text-gray-500", - // }} - /> - - - - {/* val + " km/h", - }} - animation={{ - show: true, - duration: 3000, - easing: "bounceIn", - }} - style={{ backgroundColor: "yellow" }} - /> */} - -

Testing All Gauge Widget Props

- - - - `Hello ${v} km/h`} - // labelFormat="relative" - // labelFormat="date" - labelText={(ts) => `Refreshed at ${new Date(ts).toLocaleTimeString()}`} // format="bytes" - // formatOptions={{"binary":true,"precision":2}} - - // value={1234567.891} - // format="number" - // formatOptions={{"locale":"de-DE","precision":2}} - /> - - - - { - if (!data) { - return { - title: "No Data", - color: "#6b7280", - }; - } - - const isCritical = data.value > 70; - const isWarning = data.value > 40 && data.value <= 60; - - return { - // top-level scalar/config overrides - title: isCritical ? "Critical" : isWarning ? "Warning" : "Normal", - color: isCritical ? "#ef4444" : isWarning ? "#f59e0b" : "#10b981", - unit: "Β°C", - formatValue: (v) => `${v.toFixed(1)}`, - labelText: (ts) => `Sampled ${new Date(ts).toLocaleTimeString()}`, - needle: { needleColor: isCritical ? "#ef4444" : "#10b981" }, - track: { color: isCritical ? "#450a0a" : "#052e2b" }, - animation: { duration: isCritical ? 400 : 1000 }, - - // per-slot class overrides β€” merges with (doesn't replace) the static `styles` prop - styles: { - value: isCritical - ? "text-red-500 animate-pulse" - : "text-yellow-500", - title: isCritical ? "text-red-400" : "text-slate-400", - }, - }; - }} - /> - - ( -
- ⚠ Sensor unreachable - {error} -
- )} - renderEmpty={() => ( - β€” no reading yet β€” - )} - /> - - - - - - - -
- ); -} - diff --git a/test/my-app/src/Test.tsx b/test/my-app/src/Test.tsx deleted file mode 100644 index da9c986f..00000000 --- a/test/my-app/src/Test.tsx +++ /dev/null @@ -1,1335 +0,0 @@ -// import React from "react"; -// import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -// import { CardWidget } from "../../../src"; -// import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -// import "../../../dist/styles.css"; - -// import { relativeTime } from "../../../src/helpers/formatters"; -// const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -// const token = -// "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; -// const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; - -// const anedya = new Anedya(); -// const config = anedya.newConfig(tokenId, token); -// const client = anedya.newClient(config); -// const node = anedya.newNode(client, nodeId); - -// /** -// * A reusable theme, shareable across every CardWidget instance in your -// * app. Only specify the slots you actually want to change from the -// * built-in default β€” anything omitted falls back to lightTheme/darkTheme. -// */ -// const emeraldTheme = { -// classNames: { -// container: "bg-emerald-50 border-emerald-200", -// title: "text-emerald-700", -// value: "text-emerald-900", -// label: "text-emerald-500", -// }, -// }; - - -// const commonProps = { node, variable: "humidity" }; - -// export default function App() { -// return ( - -//
- -// `Last synced ${relativeTime(ts)}`} - -// /> - - -// {/* ============================================================ -// * 2. theme β€” a reusable, shareable WidgetTheme object. Same -// * effect across every widget instance that uses it. -// * ============================================================ */} -// - -// {/* Built-in preset names also work directly: */} -// - -// {/* ============================================================ -// * 3. styles vs className β€” THE distinction to understand: -// * -// * - `styles` (plural, an OBJECT): per-SLOT overrides. -// * Keys are "container" | "title" | "value" | "unit" | "label" -// * β€” lets you reach INSIDE the widget and style individual -// * pieces independently. -// * -// * - `className` (singular, a STRING): the ordinary React -// * convention β€” one class applied ONLY to the widget's -// * outermost container element, same as you'd pass to any -// * other component. It's merged (via twMerge) with whatever -// * styles.container already resolved to, not a -// * replacement for it. -// * -// * This example uses BOTH at once so the difference is visible: -// * className adds a shadow to the outer box, styles.value/ -// * styles.title style two INNER pieces independently. -// * ============================================================ */} -// - -// {/* ============================================================ -// * 4. Plain CSS classes β€” styles works with ANY class source, -// * not just Tailwind. These reference plain hand-written CSS -// * classes (e.g. defined in a .css file this app already imports). -// * ============================================================ */} -// {/* */} - -// {/* ============================================================ -// * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` -// * work exactly as they do anywhere else in your app, because -// * styles just forwards whatever string you write straight -// * to `className`. This widget does NOT have its own custom -// * breakpoint system β€” these prefixes are compiled by YOUR -// * project's Tailwind config and respond to the BROWSER VIEWPORT, -// * same as native Tailwind everywhere else. If your own -// * tailwind.config.js customizes `theme.screens`, these prefixes -// * automatically follow that customization too β€” nothing to -// * configure on the widget's side. -// * ============================================================ */} -// {/* */} - -// {/* ============================================================ -// * 6. formatValue / labelText β€” simple formatting hooks, distinct -// * from styling. formatValue controls the displayed number's -// * text; labelText controls the caption under it. -// * ============================================================ */} -// {/* `${v.toFixed(2)} % RH`} -// labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - -// /> */} - -// {/* ============================================================ -// * 7. onStyleChange β€” conditional class overrides driven by the -// * RAW fetched data ({ value, timestamp }), always applied on top -// * of everything else (theme, styles, className). -// * ============================================================ */} -// {/* { -// if (!data) return; - -// if (data.value > 80) { -// return { -// title: "High Humidity", -// theme: "dark", -// styles: { -// value: "text-red-500" -// } -// }; -// } - -// return { -// title: "Humidity", -// theme: "light" -// }; -// }} - -// /> */} - -// {/* ============================================================ -// * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, -// * applied as inline styles on the container, independent of the -// * whole styles/theme system. -// * ============================================================ */} -// {/* */} - - -// {/* { -// // "Hello"; -// // }, -// // }} -// // labels={{ -// // show: true, -// // position: "outside", -// // }} -// // scale={{ -// // minLabel: "Hello", -// // maxLabel: "World", -// // }} -// // ticks={{ -// // show: true, -// // count: 10, -// // position: "outside", -// // length: 10, -// // labels: true, -// // }} -// animation={{ -// duration: 4000, -// easing: "easeElasticOut", // easeCubicOut, easeElasticOut -// }} -// // tooltip={{ -// // show:false, -// // }} -// // classNames={{ -// // title: "text-white", -// // tickLabel: "text-white text-lg", -// // label: "text-red", -// // value: "text-white", -// // }} -// theme="dark" -// /> */} - -// - -// - -// -// style={{ -// backgroundColor: "#1e1e2f", -// borderRadius: "16px", -// padding: "10px", -// }} -// // 'styles' affects specific internal SVG/HTML slots via Tailwind classes -// styles={{ -// container: "border border-gray-700", // merges with outer wrapper -// title: "text-purple-400 text-xs uppercase tracking-wider", -// value: "text-white text-2xl font-mono", -// unit: "text-gray-400 text-sm", -// label: "text-gray-500 text-[10px]", -// bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients -// needle: "stroke-pink-400 stroke-2", -// needleCap: "fill-pink-400", -// }} -// /> - -// - -// - -// - -// {/* // 1. Show a custom static text */} -// "Last reading"} // Always shows "Last reading" -// /> - -// {/* // 2. Format the timestamp exactly how you want */} -// -// `Updated at ${new Date(timestamp).toLocaleString("en-US", { -// hour: "2-digit", -// minute: "2-digit", -// second: "2-digit", -// })}` -// } -// // Output: "Updated at 02:30:45 PM" -// /> - -// {/* // 3. Show relative time with custom wording */} -// { -// const diff = Math.floor((Date.now() - timestamp) / 60000); -// if (diff < 1) return "Just now"; -// if (diff < 60) return `${diff} min ago`; -// return `${Math.floor(diff / 60)} hours ago`; -// }} -// /> - -// {/* // 4. Hide the label entirely (return null or empty string) */} -// null} // No label shown -// /> -//
-// ); -// } - -{ - /* -//create react app -//link public-widget-sdk -//npm run dev -//send this file tp yash to copy paste */ -} - - - -// import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -// import * as d3 from "d3"; -// import { twMerge } from "tailwind-merge"; -// import { AnedyaWidgetBaseProps } from "../../common"; -// import { SlotClassNames, WidgetTheme } from "../../types/root"; -// import { -// GaugeAnimationConfig, -// GaugeArcConfig, -// GaugeBarSpec, -// GaugeColor, -// GaugeLabelsConfig, -// GaugeNeedleConfig, -// GaugeNeedleLabelConfig, -// GaugeScaleConfig, -// GaugeSegment, -// GaugeSlot, -// GaugeThreshold, -// GaugeTicksConfig, -// GaugeTooltipConfig, -// GaugeTrackConfig, -// GaugeValueLabelConfig, -// GaugeVariant, -// } from "../../types/gauge"; -// import { -// DEFAULT_GAUGE_THEME, -// GAUGE_DEFAULT_CLASSES, -// gaugeDarkTheme, -// gaugeLightTheme, -// } from "../../themes/gaugeTheme"; -// import { useResizeObserver } from "../../hooks/useResizeObserver"; - -// export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { -// variant?: GaugeVariant; -// /** Used before live data arrives, or standalone in dummy-data mode. */ -// value?: number; -// min?: number; -// max?: number; -// size?: number; -// responsive?: boolean; - -// arc?: GaugeArcConfig; -// track?: GaugeTrackConfig; -// fillMode?: "progress" | "solid"; -// /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ -// color?: GaugeColor; -// bars?: GaugeBarSpec[]; - -// needle?: GaugeNeedleConfig; -// labels?: GaugeLabelsConfig; -// valueLabel?: GaugeValueLabelConfig; -// needleLabel?: GaugeNeedleLabelConfig; -// scale?: GaugeScaleConfig; -// ticks?: GaugeTicksConfig; -// segments?: GaugeSegment[]; -// thresholds?: GaugeThreshold[]; -// animation?: GaugeAnimationConfig; -// tooltip?: GaugeTooltipConfig; - -// classNames?: SlotClassNames; -// style?: React.CSSProperties; - -// onClick?: (value: number) => void; -// onHover?: (value: number | null) => void; -// onValueChange?: (value: number) => void; -// } - -// const DEG2RAD = Math.PI / 180; - -// const DEFAULT_ARC: Required> = { -// startAngle: -90, -// endAngle: 90, -// cornerRadius: 0, -// gap: 6, -// }; - -// const DEFAULT_ANIMATION: Required = { -// duration: 750, -// easing: "easeCubicOut", -// }; - -// function resolveEase(name: string) { -// return (d3 as any)[name] ?? d3.easeCubicOut; -// } - -// function needlePixelLength( -// length: GaugeNeedleConfig["length"], -// radius: number -// ) { -// if (typeof length === "number") return length; -// switch (length) { -// case "short": -// return radius * 0.55; -// case "full": -// return radius * 0.95; -// case "medium": -// default: -// return radius * 0.75; -// } -// } - -// /** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ -// function needleShape( -// type: NonNullable, -// length: number, -// width: number -// ) { -// const w = width; -// switch (type) { -// case "line": -// return { -// tag: "line", -// attrs: { -// x1: 0, -// y1: 0, -// x2: 0, -// y2: -length, -// strokeWidth: w, -// strokeLinecap: "butt", -// }, -// }; -// case "rounded": -// return { -// tag: "line", -// attrs: { -// x1: 0, -// y1: 0, -// x2: 0, -// y2: -length, -// strokeWidth: w, -// strokeLinecap: "round", -// }, -// }; -// case "triangle": { -// const half = w / 2; -// return { -// tag: "polygon", -// attrs: { -// points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ -// -length * 0.15 -// }`, -// }, -// }; -// } -// case "drop": -// default: { -// const half = w / 2; -// // Teardrop: rounded base, sharp tip. -// const d = `M ${-half} 0 -// C ${-half} ${-length * 0.35}, ${-w} ${ -// -length * 0.7 -// }, 0 ${-length} -// C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 -// A ${half} ${half} 0 1 1 ${-half} 0 Z`; -// return { tag: "path", attrs: { d } }; -// } -// } -// } - -// function isGradientColor(c?: GaugeColor): c is string[] { -// return Array.isArray(c) && c.length >= 2; -// } - -// /** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ -// function resolveFill( -// defs: d3.Selection, -// id: string, -// color: GaugeColor | undefined, -// fallback: string -// ): string { -// if (!color) return fallback; -// if (!isGradientColor(color)) return color; - -// let grad = defs.select(`#${id}`); -// if (grad.empty()) { -// grad = defs.append("linearGradient").attr("id", id); -// } -// grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); -// grad.selectAll("stop").remove(); -// color.forEach((c, i) => -// grad -// .append("stop") -// .attr("offset", `${(i / (color.length - 1)) * 100}%`) -// .attr("stop-color", c) -// ); -// return `url(#${id})`; -// } - -// /** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ -// function getArcBounds(startDeg: number, endDeg: number) { -// const lo = Math.min(startDeg, endDeg); -// const hi = Math.max(startDeg, endDeg); -// const angles = [startDeg, endDeg]; -// for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); - -// let minX = Infinity, -// maxX = -Infinity, -// minY = Infinity, -// maxY = -Infinity; -// angles.forEach((deg) => { -// const a = deg * DEG2RAD; -// const x = Math.sin(a); -// const y = -Math.cos(a); -// minX = Math.min(minX, x); -// maxX = Math.max(maxX, x); -// minY = Math.min(minY, y); -// maxY = Math.max(maxY, y); -// }); -// return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; -// } - -// export function GaugeWidget({ -// node, -// variable, -// title, -// theme, -// className, -// style, -// width, -// height, -// minWidth = 160, -// maxWidth = 480, -// minHeight = 160, -// maxHeight = 480, -// aspectRatio, - -// variant = "progress", -// value: valueProp, -// min = 0, -// max = 100, -// size, -// responsive = true, - -// arc, -// track, -// fillMode = "progress", -// color, -// bars, - -// needle, -// labels, -// valueLabel, -// needleLabel, -// scale, -// ticks, -// segments, -// thresholds, -// animation, -// tooltip, - -// classNames = {}, -// onClick, -// onHover, -// onValueChange, -// }: GaugeWidgetProps) { -// const svgRef = useRef(null); -// const tooltipRef = useRef(null); -// const prevValueRef = useRef(min); - -// const [fetchedValue, setFetchedValue] = useState(null); -// const [hoverValue, setHoverValue] = useState(null); - -// // ---- Live data fetch (mirrors CardWidget) ---- -// useEffect(() => { -// if (!node) return; -// let mounted = true; - -// node -// .getLatestData(variable) -// .then((res: any) => { -// if (!mounted) return; -// if (res?.isSuccess && res?.isDataAvailable) { -// setFetchedValue(res.data.value); -// } -// }) -// .catch(() => { -// /* fall back to `value` prop / dummy data silently */ -// }); - -// return () => { -// mounted = false; -// }; -// }, [node, variable]); - -// const rawValue = fetchedValue ?? valueProp ?? min; -// const clampedValue = Math.min(max, Math.max(min, rawValue)); - -// useEffect(() => { -// onValueChange?.(clampedValue); -// }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps - -// // ---- Responsive sizing ---- -// const { ref: wrapperRef, size: dims } = useResizeObserver( -// responsive && size == null -// ); - -// // ---- Resolved config (defaults per variant) ---- -// const resolvedArc = { ...DEFAULT_ARC, ...arc }; - -// const resolvedTrack: Required = { -// show: track?.show ?? true, -// color: track?.color ?? "", -// }; - -// const needleShownByDefault = variant === "progress" || variant === "needle"; - -// const resolvedNeedle: Required> & { -// length: NonNullable; -// } = { -// show: needle?.show ?? needleShownByDefault, -// type: needle?.type ?? "rounded", -// length: needle?.length ?? "medium", -// width: needle?.width ?? 4, -// color: needle?.color ?? "", -// capRadius: needle?.capRadius ?? 6, -// animation: needle?.animation ?? true, -// }; - -// const resolvedLabels: Required = { -// show: labels?.show ?? true, -// position: labels?.position ?? "outside", -// }; - -// const resolvedValueLabel: Required< -// Omit -// > & { formatter?: (v: number) => string } = { -// show: valueLabel?.show ?? true, -// precision: valueLabel?.precision ?? 0, -// prefix: valueLabel?.prefix ?? "", -// suffix: valueLabel?.suffix ?? "", -// formatter: valueLabel?.formatter, -// }; - -// const resolvedNeedleLabel: Required< -// Omit -// > & { formatter?: (v: number) => string } = { -// show: needleLabel?.show ?? false, -// formatter: needleLabel?.formatter, -// }; - -// const resolvedTicks: Required = { -// show: ticks?.show ?? (variant === "needle" || variant === "segmented"), -// count: ticks?.count ?? 5, -// position: ticks?.position ?? "outside", -// length: ticks?.length ?? 6, -// labels: ticks?.labels ?? true, -// }; - -// const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; - -// const resolvedTooltip: Required = { -// show: tooltip?.show ?? true, -// }; - -// // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- -// const resolvedTheme: WidgetTheme = -// theme === "dark" -// ? gaugeDarkTheme -// : theme === "light" -// ? gaugeLightTheme -// : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; - -// const resolveSlot = useCallback( -// (slot: GaugeSlot) => -// twMerge( -// GAUGE_DEFAULT_CLASSES[slot], -// resolvedTheme.styles[slot], -// classNames[slot] -// ), -// [resolvedTheme, classNames] -// ); - -// const boxWidth = size ?? width ?? (dims.width || 240); - -// const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); - -// const bounds = useMemo( -// () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), -// [resolvedArc.startAngle, resolvedArc.endAngle] -// ); - -// const pad = 8; -// // Reserve room below the arc for value/needle-label/variable text so -// // the dome never gets crowded β€” bigger reserve when the value label is on. -// const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; - -// // Ticks (and their number labels) draw *outside* the arc's own radius, -// // so the radius-fit math below must shrink the arc enough to leave -// // room for them β€” otherwise tick labels get clipped by the SVG -// // viewBox, which looked like "some ticks are hidden". -// const tickOverflow = -// resolvedTicks.show && resolvedTicks.position !== "inside" -// ? resolvedTicks.length + (resolvedTicks.labels ? 26 : 8) -// : 0; -// // Scale min/max labels also draw past the arc's radius at the two ends. -// const scaleLabelOverflow = -// resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) ? 24 : 0; -// const edgeOverflow = Math.max(tickOverflow, scaleLabelOverflow); - -// const availW = boxWidth - pad * 2 - edgeOverflow * 2; -// const availH = boxHeight * (1 - textReserve) - pad * 2 - edgeOverflow; - -// const outerRadius = -// resolvedArc.radius ?? -// Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); - -// const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); - -// // Center the arc's bounding box within the available width, anchor its top at `pad`. -// const cx = -// pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; -// const cy = pad - bounds.minY * outerRadius; - -// const angleScale = useMemo( -// () => -// d3 -// .scaleLinear() -// .domain([min, max]) -// .range([ -// resolvedArc.startAngle * DEG2RAD, -// resolvedArc.endAngle * DEG2RAD, -// ]) -// .clamp(true), -// [min, max, resolvedArc.startAngle, resolvedArc.endAngle] -// ); - -// // ---- D3 draw ---- -// useEffect(() => { -// if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; - -// const svg = d3.select(svgRef.current); -// const defs = svg.select("defs"); -// const root = svg.select("g.anedya-gauge-root"); -// root.attr("transform", `translate(${cx},${cy})`); - -// const ease = resolveEase(resolvedAnimation.easing); -// const arcGen = d3 -// .arc<{ startAngle: number; endAngle: number; r: number }>() -// .innerRadius((d) => d.r - thickness) -// .outerRadius((d) => d.r) -// .cornerRadius(resolvedArc.cornerRadius) -// .startAngle((d) => d.startAngle) -// .endAngle((d) => d.endAngle); - -// const startA = resolvedArc.startAngle * DEG2RAD; -// const endA = resolvedArc.endAngle * DEG2RAD; - -// // --- Track --- -// const trackSel = root.select( -// "path.anedya-gauge-track-path" -// ); -// if (resolvedTrack.show && variant !== "multiBar") { -// trackSel -// .attr( -// "d", -// arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! -// ) -// .attr("fill", resolvedTrack.color || "currentColor") -// .attr("opacity", 1); -// } else { -// trackSel.attr("opacity", 0); -// } - -// // --- Bar (progress / solid / segmented base) --- -// const barGroup = root.select("g.anedya-gauge-bar-group"); -// barGroup.selectAll("*").remove(); - -// if (variant === "multiBar" && bars?.length) { -// const maxBars = bars.slice(0, 10); -// maxBars.forEach((bar, i) => { -// const r = outerRadius - i * (thickness + resolvedArc.gap); -// if (resolvedTrack.show) { -// barGroup -// .append("path") -// .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) -// .attr( -// "class", -// twMerge("anedya-gauge-multibar-track", resolveSlot("track")) -// ) -// .attr("fill", resolvedTrack.color || "currentColor") -// .attr("stroke", "none"); -// } -// const valAngle = d3 -// .scaleLinear() -// .domain([min, max]) -// .range([startA, endA]) -// .clamp(true)(bar.value); - -// const barFill = resolveFill( -// defs, -// `anedya-gauge-bar-fill-${i}`, -// bar.color, -// "currentColor" -// ); - -// const path = barGroup -// .append("path") -// .attr("class", resolveSlot("bar")) -// .attr("fill", barFill) -// .attr("stroke", "none"); -// path -// .datum({ startAngle: startA, endAngle: startA, r }) -// .attr("d", arcGen as any) -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("d", function (d: any) { -// const i2 = d3.interpolate(d.endAngle, valAngle); -// return (t) => { -// d.endAngle = i2(t); -// return arcGen(d)!; -// }; -// }); -// }); -// } else if (segments?.length) { -// const scaleAngle = d3 -// .scaleLinear() -// .domain([min, max]) -// .range([startA, endA]) -// .clamp(true); -// // Half the configured gap, converted from px to radians at this radius, -// // so adjoining segments get visible separation like distinct blocks. -// const gapRad = resolvedArc.gap / 2 / outerRadius || 0; - -// const segArcGen = d3 -// .arc<{ startAngle: number; endAngle: number; r: number }>() -// .innerRadius((d) => d.r - thickness) -// .outerRadius((d) => d.r) -// .cornerRadius(resolvedArc.cornerRadius || thickness / 4) -// .startAngle((d) => d.startAngle) -// .endAngle((d) => d.endAngle); - -// segments.forEach((seg, idx) => { -// const segStart = scaleAngle(seg.from) + gapRad; -// const segEnd = scaleAngle(seg.to) - gapRad; -// if (segEnd <= segStart) return; - -// const fill = resolveFill( -// defs, -// `anedya-gauge-segment-fill-${idx}`, -// seg.color, -// "currentColor" -// ); -// barGroup -// .append("path") -// .attr("class", resolveSlot("segment")) -// .attr("fill", fill) -// .attr("stroke", "none") -// .attr( -// "d", -// segArcGen({ -// startAngle: segStart, -// endAngle: segEnd, -// r: outerRadius, -// })! -// ); -// }); -// } else { -// const valueAngle = angleScale(clampedValue); -// const barColorRaw: GaugeColor | undefined = -// color ?? -// (thresholds?.length -// ? [...thresholds] -// .sort((a, b) => a.value - b.value) -// .reduce( -// (acc, th) => (clampedValue >= th.value ? th.color : acc), -// thresholds[0].color -// ) -// : undefined); - -// const barFill = resolveFill( -// defs, -// "anedya-gauge-bar-fill", -// barColorRaw, -// "currentColor" -// ); - -// const path = barGroup -// .append("path") -// .attr("class", resolveSlot("bar")) -// .attr("fill", barFill) -// .attr("stroke", "none"); - -// const from = fillMode === "solid" ? startA : startA; -// const to = fillMode === "solid" ? endA : valueAngle; - -// path -// .datum({ -// startAngle: startA, -// endAngle: -// prevValueRef.current != null -// ? angleScale(prevValueRef.current) -// : startA, -// r: outerRadius, -// }) -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("d", function (d: any) { -// const i2 = d3.interpolate(d.endAngle, to); -// return (t) => { -// d.endAngle = i2(t); -// return arcGen({ -// startAngle: from, -// endAngle: d.endAngle, -// r: outerRadius, -// })!; -// }; -// }); -// } - -// // --- Ticks --- -// const tickGroup = root.select("g.anedya-gauge-ticks"); -// tickGroup.selectAll("*").remove(); -// if (resolvedTicks.show) { -// const count = Math.max(2, resolvedTicks.count); -// const tickR = -// resolvedTicks.position === "inside" -// ? outerRadius - thickness -// : resolvedTicks.position === "cross" -// ? outerRadius - thickness / 2 -// : outerRadius + 4; -// d3.range(count).forEach((i) => { -// const t = i / (count - 1); -// const tv = min + t * (max - min); -// const a = angleScale(tv); -// const x1 = Math.sin(a) * tickR; -// const y1 = -Math.cos(a) * tickR; -// const x2 = -// Math.sin(a) * -// (tickR + -// (resolvedTicks.position === "inside" -// ? -resolvedTicks.length -// : resolvedTicks.length)); -// const y2 = -// -Math.cos(a) * -// (tickR + -// (resolvedTicks.position === "inside" -// ? -resolvedTicks.length -// : resolvedTicks.length)); -// tickGroup -// .append("line") -// .attr("class", resolveSlot("tick")) -// .attr("stroke", "currentColor") -// .attr("x1", x1) -// .attr("y1", y1) -// .attr("x2", x2) -// .attr("y2", y2); - -// if (resolvedTicks.labels) { -// const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); -// const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); -// tickGroup -// .append("text") -// .attr("class", resolveSlot("tickLabel")) -// .attr("x", lx) -// .attr("y", ly) -// .attr("text-anchor", "middle") -// .attr("dominant-baseline", "middle") -// .text(String(Math.round(tv))); -// } -// }); -// } -// // --- Scale min/max labels (drawn at the arc's real start/end points, -// // not floated at the container's edges) --- -// const scaleLabelGroup = root.select( -// "g.anedya-gauge-scale-labels" -// ); -// scaleLabelGroup.selectAll("*").remove(); -// if (resolvedLabels.show && (scale?.minLabel || scale?.maxLabel)) { -// const labelR = -// outerRadius + -// (resolvedTicks.show ? resolvedTicks.length + 16 : 12); - -// const drawScaleLabel = (angle: number, text: string) => { -// const x = Math.sin(angle) * labelR; -// const y = -Math.cos(angle) * labelR; -// // Anchor away from the point so the label doesn't overlap the arc: -// // labels on the left side end at x, labels on the right start at x. -// const anchor = x < -2 ? "end" : x > 2 ? "start" : "middle"; -// scaleLabelGroup -// .append("text") -// .attr("class", resolveSlot("scaleLabel")) -// .attr("x", x) -// .attr("y", y) -// .attr("text-anchor", anchor) -// .attr("dominant-baseline", "middle") -// .text(text); -// }; - -// if (scale?.minLabel) drawScaleLabel(startA, scale.minLabel); -// if (scale?.maxLabel) drawScaleLabel(endA, scale.maxLabel); -// } - -// // --- Needle --- -// const needleGroup = root.select("g.anedya-gauge-needle"); -// if (resolvedNeedle.show && variant !== "multiBar") { -// const len = needlePixelLength(resolvedNeedle.length, outerRadius); -// const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); - -// needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); -// const needleEl = needleGroup.insert( -// shape.tag as any, -// "circle.anedya-gauge-needle-cap" -// ); -// needleEl -// .attr("class", resolveSlot("needle")) -// .attr("fill", resolvedNeedle.color || "currentColor") -// .attr("stroke", resolvedNeedle.color || "currentColor"); -// Object.entries(shape.attrs).forEach(([k, v]) => -// needleEl.attr( -// k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), -// v as any -// ) -// ); - -// let cap = needleGroup.select( -// "circle.anedya-gauge-needle-cap" -// ); -// if (cap.empty()) { -// cap = needleGroup -// .append("circle") -// .attr( -// "class", -// twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) -// ); -// } -// cap -// .attr("r", resolvedNeedle.capRadius) -// .attr("fill", resolvedNeedle.color || "currentColor"); - -// const targetDeg = angleScale(clampedValue) / DEG2RAD; -// if (resolvedNeedle.animation) { -// needleGroup -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("transform", function () { -// const current = needleGroup.attr("data-angle") -// ? +needleGroup.attr("data-angle")! -// : startA / DEG2RAD; -// const interp = d3.interpolate(current, targetDeg); -// return (t) => { -// const a = interp(t); -// needleGroup.attr("data-angle", String(a)); -// return `rotate(${a})`; -// }; -// }); -// } else { -// needleGroup -// .attr("transform", `rotate(${targetDeg})`) -// .attr("data-angle", String(targetDeg)); -// } -// needleGroup.attr("opacity", 1); -// } else { -// needleGroup.attr("opacity", 0); -// } - -// prevValueRef.current = clampedValue; -// }, [ -// boxWidth, -// boxHeight, -// cx, -// cy, -// outerRadius, -// thickness, -// variant, -// clampedValue, -// min, -// max, -// fillMode, -// color, -// JSON.stringify(bars), -// JSON.stringify(segments), -// JSON.stringify(thresholds), -// resolvedTrack.show, -// resolvedTrack.color, -// resolvedNeedle.show, -// resolvedNeedle.type, -// resolvedNeedle.length, -// resolvedNeedle.width, -// resolvedNeedle.color, -// resolvedNeedle.capRadius, -// resolvedNeedle.animation, -// resolvedTicks.show, -// resolvedTicks.count, -// resolvedTicks.position, -// resolvedTicks.length, -// resolvedTicks.labels, -// resolvedAnimation.duration, -// resolvedAnimation.easing, -// resolveSlot, -// resolvedLabels.show, -// scale?.minLabel, -// scale?.maxLabel, -// ]); - -// // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- -// const handlePointerMove = useCallback( -// (e: React.PointerEvent) => { -// if (!resolvedTooltip.show && !onHover) return; -// const rect = svgRef.current!.getBoundingClientRect(); -// const x = e.clientX - rect.left - cx; -// const y = e.clientY - rect.top - cy; -// const dist = Math.hypot(x, y); -// if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { -// setHoverValue(null); -// onHover?.(null); -// return; -// } -// let a = Math.atan2(x, -y); -// const hv = angleScale.invert(a); -// const clamped = Math.min(max, Math.max(min, hv)); -// setHoverValue(clamped); -// onHover?.(clamped); -// if (tooltipRef.current) { -// tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; -// tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; -// } -// }, -// [ -// cx, -// cy, -// outerRadius, -// thickness, -// angleScale, -// min, -// max, -// onHover, -// resolvedTooltip.show, -// ] -// ); - -// const handlePointerLeave = useCallback(() => { -// setHoverValue(null); -// onHover?.(null); -// }, [onHover]); - -// const handleClick = useCallback( -// () => onClick?.(clampedValue), -// [onClick, clampedValue] -// ); - -// const formattedValue = resolvedValueLabel.formatter -// ? resolvedValueLabel.formatter(clampedValue) -// : `${resolvedValueLabel.prefix}${clampedValue.toFixed( -// resolvedValueLabel.precision -// )}${resolvedValueLabel.suffix}`; - -// const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); - -// return ( -//
-// {title && {title}} - -// -// -// -// -// -// -// -// -// -// -// -// - -// {/* {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( -//
-// {scale?.minLabel} -// {scale?.maxLabel} -//
-// )} */} - -// {resolvedValueLabel.show && ( -// {formattedValue} -// )} - -// {resolvedNeedleLabel.show && needleLabelText && ( -// {needleLabelText} -// )} - -// {variable && {variable}} - -// {resolvedTooltip.show && hoverValue != null && ( -//
-// {hoverValue.toFixed(resolvedValueLabel.precision)} -//
-// )} -//
-// ); -// } diff --git a/test/my-app/src/assets/hero.png b/test/my-app/src/assets/hero.png deleted file mode 100644 index cc51a3d20ad4bc961b596a6adfd686685cd84bb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44919 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 JPDHLkV1myZcL)Fg diff --git a/test/my-app/src/assets/react.svg b/test/my-app/src/assets/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/test/my-app/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/test/my-app/src/assets/vite.svg b/test/my-app/src/assets/vite.svg deleted file mode 100644 index 5101b674..00000000 --- a/test/my-app/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ -Vite diff --git a/test/my-app/src/globals.css b/test/my-app/src/globals.css deleted file mode 100644 index 43ce5c51..00000000 --- a/test/my-app/src/globals.css +++ /dev/null @@ -1,54 +0,0 @@ -@import "tailwindcss"; - -:root { - --background: 0 0% 100%; - --foreground: 222 47% 11%; - --card: 0 0% 100%; - --card-foreground: 222 47% 11%; - --border: 214 32% 91%; - --muted-foreground: 215 16% 47%; - --primary: 221 83% 53%; - --secondary: 262 83% 58%; - --destructive: 0 84% 60%; - --radius: 0.75rem; -} - -.dark { - --background: 222 47% 11%; - --foreground: 210 40% 98%; - --card: 222 47% 15%; - --card-foreground: 210 40% 98%; - --border: 217 33% 24%; - --muted-foreground: 215 20% 65%; - --primary: 217 91% 60%; - --secondary: 262 83% 68%; - --destructive: 0 63% 60%; - --radius: 0.75rem; -} - -.my-card { - background: #1e1b4b; - border: 1px solid #4338ca; - border-radius: 10px; - padding: 18px; -} - -.my-card-title { - color: #a5b4fc; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.my-card-value { - color: #eef2ff; - font-size: 42px; - font-weight: 800; - font-variant-numeric: tabular-nums; -} - -.my-card-label { - color: #818cf8; - font-size: 11px; -} \ No newline at end of file diff --git a/test/my-app/src/index.css b/test/my-app/src/index.css deleted file mode 100644 index 393a406c..00000000 --- a/test/my-app/src/index.css +++ /dev/null @@ -1,113 +0,0 @@ -@import "tailwindcss"; - -:root { - --text: #6b6375; - --text-h: #08060d; - --bg: #fff; - --border: #e5e4e7; - --code-bg: #f4f3ec; - --accent: #aa3bff; - --accent-bg: rgba(170, 59, 255, 0.1); - --accent-border: rgba(170, 59, 255, 0.5); - --social-bg: rgba(244, 243, 236, 0.5); - --shadow: - rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px; - - --sans: system-ui, 'Segoe UI', Roboto, sans-serif; - --heading: system-ui, 'Segoe UI', Roboto, sans-serif; - --mono: ui-monospace, Consolas, monospace; - - font: 18px/145% var(--sans); - letter-spacing: 0.18px; - color-scheme: light dark; - color: var(--text); - background: var(--bg); - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - @media (max-width: 1024px) { - font-size: 16px; - } -} - -@media (prefers-color-scheme: dark) { - :root { - --text: #9ca3af; - --text-h: #f3f4f6; - --bg: #16171d; - --border: #2e303a; - --code-bg: #1f2028; - --accent: #c084fc; - --accent-bg: rgba(192, 132, 252, 0.15); - --accent-border: rgba(192, 132, 252, 0.5); - --social-bg: rgba(47, 48, 58, 0.5); - --shadow: - rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px; - } - - #social .button-icon { - filter: invert(1) brightness(2); - } -} - -body { - margin: 0; -} - -#root { - width: 1126px; - max-width: 100%; - margin: 0 auto; - text-align: center; - border-inline: 1px solid var(--border); - min-height: 100svh; - display: flex; - flex-direction: column; - box-sizing: border-box; -} - -h1, -h2 { - font-family: var(--heading); - font-weight: 500; - color: var(--text-h); -} - -h1 { - font-size: 56px; - letter-spacing: -1.68px; - margin: 32px 0; - @media (max-width: 1024px) { - font-size: 36px; - margin: 20px 0; - } -} -h2 { - font-size: 24px; - line-height: 118%; - letter-spacing: -0.24px; - margin: 0 0 8px; - @media (max-width: 1024px) { - font-size: 20px; - } -} -p { - margin: 0; -} - -code, -.counter { - font-family: var(--mono); - display: inline-flex; - border-radius: 4px; - color: var(--text-h); -} - -code { - font-size: 15px; - line-height: 135%; - padding: 4px 8px; - background: var(--code-bg); -} diff --git a/test/my-app/src/main.jsx b/test/my-app/src/main.jsx deleted file mode 100644 index b9a1a6de..00000000 --- a/test/my-app/src/main.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from 'react' -import { createRoot } from 'react-dom/client' -import './index.css' -import App from './App.jsx' - -createRoot(document.getElementById('root')).render( - - - , -) diff --git a/test/my-app/vite.config.js b/test/my-app/vite.config.js deleted file mode 100644 index 65fb8852..00000000 --- a/test/my-app/vite.config.js +++ /dev/null @@ -1,24 +0,0 @@ -import { defineConfig } from 'vite' -import react, { reactCompilerPreset } from '@vitejs/plugin-react' -import babel from '@rolldown/plugin-babel' -import tailwindcss from "@tailwindcss/vite"; - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [ - react(), - babel({ presets: [reactCompilerPreset()] }), - tailwindcss() - ], - resolve: { - dedupe: ["react", "react-dom", "@base-ui/react"], - }, - server: { - fs: { - // Allow Vite to fetch assets from the parent widget SDK directory - allow: ['..'] - } - } - -}) - From 3792cb8c053335d732869bdec995ac67bca12298 Mon Sep 17 00:00:00 2001 From: abhishreecodes Date: Tue, 28 Jul 2026 13:52:53 +0530 Subject: [PATCH 55/66] Improve widget API, documentation and example application - Add support for manually supplied values in AnedyaCard - Make node optional when a custom value is provided - Validate that either node or value is supplied for both widgets - Rename widgets to AnedyaCard and AnedyaGauge - Rename package to anedya-widgets-react - Add README for the example application - Update SDK README documentation and package description - Fix npm badge and repository URLs - Hardcode example application credentials for easier setup - Remove unused React/Vite assets from the example application - Add dist and test folders to .gitignore --- .gitignore | 3 +- CONTRIBUTING.md | 14 +- README.md | 225 +-- dist/index.d.mts | 99 -- examples/application-example/README.md | 195 ++- .../application-example/package-lock.json | 99 +- examples/application-example/package.json | 2 +- examples/application-example/src/App.jsx | 62 +- examples/application-example/src/Test.tsx | 1335 ----------------- .../application-example/src/assets/hero.png | Bin 44919 -> 0 bytes .../application-example/src/assets/react.svg | 1 - .../application-example/src/assets/vite.svg | 1 - package-lock.json | 4 +- package.json | 4 +- src/common.ts | 32 +- src/components/AnedyaCard.tsx | 951 ++++++++++++ src/components/CardWidget.tsx | 426 ------ .../{GaugeChartWidget.tsx => AnedyaGauge.tsx} | 48 +- src/index.ts | 3 +- src/themes/defaultTheme.ts | 3 +- 20 files changed, 1448 insertions(+), 2059 deletions(-) delete mode 100644 dist/index.d.mts delete mode 100644 examples/application-example/src/Test.tsx delete mode 100644 examples/application-example/src/assets/hero.png delete mode 100644 examples/application-example/src/assets/react.svg delete mode 100644 examples/application-example/src/assets/vite.svg create mode 100644 src/components/AnedyaCard.tsx delete mode 100644 src/components/CardWidget.tsx rename src/components/GaugeChart/{GaugeChartWidget.tsx => AnedyaGauge.tsx} (95%) diff --git a/.gitignore b/.gitignore index b65549ce..193a6ea7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -tests/ +test/ +dist/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0d77609..54853301 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ This document covers internal build setup for people working on this SDK itself Since this SDK is installed as a real package (not copied into the consumer's own repo, the way shadcn/ui works), the consumer's own Tailwind build **never scans this package's source files** by default β€” so every class string in files like `themes/defaultTheme.ts` / `CARD_DEFAULT_CLASSES` compiles to nothing in their app, and every widget would render with zero layout or color. -The fix: this SDK ships its **own pre-compiled stylesheet** as part of its build, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. This is why every consumer-facing widget needs `import "public-widget-sdk/styles.css"` β€” see the README's [Stylesheet import](./README.md#stylesheet-import) section for the consumer-facing side of this. +The fix: this SDK ships its **own pre-compiled stylesheet** as part of its build, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. This is why every consumer-facing widget needs `import "anedya-widgets-react/styles.css"` β€” see the README's [Stylesheet import](./README.md#stylesheet-import) section for the consumer-facing side of this. --- @@ -99,17 +99,17 @@ npm link **2. In the demo app**, link to it: ```bash -npm link public-widget-sdk +npm link anedya-widgets-react ``` -This creates a symlink from the demo's `node_modules/public-widget-sdk` to your local package root β€” the demo now resolves that import to your local working copy instead of anything published to npm. +This creates a symlink from the demo's `node_modules/anedya-widgets-react` to your local package root β€” the demo now resolves that import to your local working copy instead of anything published to npm. ### Two ways to import while developing **Option A β€” import directly from source (fastest iteration)** ```jsx -import { CardWidget } from "../../../src"; +import { AnedyaCard } from "../../../src"; import "../../../dist/style.css"; ``` @@ -125,8 +125,8 @@ before it shows up in the demo, even in this mode. **Option B β€” import as the published package (accurate consumer simulation)** ```jsx -import { CardWidget } from "public-widget-sdk"; -import "public-widget-sdk/styles.css"; +import { AnedyaCard } from "anedya-widgets-react"; +import "anedya-widgets-react/styles.css"; ``` Use this to verify the package behaves correctly as an actual installed dependency β€” e.g. confirming `exports` map entries resolve correctly, the stylesheet subpath import works, and nothing that only exists in the local `src/` folder (but wasn't actually exported) is accidentally being relied on. @@ -150,6 +150,6 @@ Two things worth knowing if changes don't seem to show up: rm -rf node_modules/.vite npm run dev ``` -- Restart the demo's dev server (not just save/hot-reload) after switching which import block is active β€” changing which module resolves `CardWidget` can require a fresh module graph. +- Restart the demo's dev server (not just save/hot-reload) after switching which import block is active β€” changing which module resolves `AnedyaCard` can require a fresh module graph. **Rule of thumb:** use Option A day-to-day while iterating on a widget; switch to Option B before committing/publishing, as a final sanity check that the consumer-facing package actually works the way the README describes. \ No newline at end of file diff --git a/README.md b/README.md index ac16611f..1692ecd4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PyPI](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk)  [Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js) +[Anedya Documentation](https://docs.anedya.io?utm_source=github&utm_medium=link&utm_campaign=github-sdk&utm_content=js)

@@ -8,21 +8,24 @@ # Anedya Widgets SDK -A collection of pre-built, themeable React widgets for displaying Anedya IoT data β€” drop-in components for dashboards and front-end apps. +A collection of pre-built, themeable React widgets for displaying Anedya IoT data in dashboards and front-end applications. + +Designed for developers using the Anedya Frontend SDK, the library provides drop-in UI components that fetch and display device data with minimal setup. Each widget is fully customizable through themes, Tailwind classes, and component props, making it easy to match your application's design while avoiding repetitive UI implementation. ## Table of Contents - [Installation & Setup](#installation--setup) - [Widgets](#widgets) - - [CardWidget](#cardwidget) + - [AnedyaCard](#AnedyaCard) - [Required props](#required-props) + - [Manual vs live values](#manual-vs-live-values) - [The styling model](#the-styling-model) - [`styles` vs `className`](#styles-vs-classname--the-distinction-that-matters-most) - [Theming](#theming) - [Tailwind responsive utilities](#tailwind-responsive-utilities) - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering) - [How props are resolved](#how-props-are-resolved) - - [GaugeWidget](#gaugewidget) + - [AnedyaGauge](#AnedyaGauge) - [Required props](#required-props-1) - [Manual vs live values](#manual-vs-live-values) - [Slots & styling](#slots--styling) @@ -56,28 +59,28 @@ Widgets in this SDK don't create their own Anedya client or node β€” they only r **1. Install both packages:** ```bash -npm install @anedyasystems/anedya-frontend-sdk public-widget-sdk +npm install @anedyasystems/anedya-frontend-sdk anedya-widgets-react ``` **2. Import the stylesheet once**, anywhere in your app's entry point: ```jsx -import "public-widget-sdk/styles.css"; +import "anedya-widgets-react/styles.css"; ``` **3. Create a client and node using the Frontend SDK, then pass the node into any widget:** ```jsx import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "public-widget-sdk"; -import "public-widget-sdk/styles.css"; +import { AnedyaCard } from "anedya-widgets-react"; +import "anedya-widgets-react/styles.css"; const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); const client = anedya.newClient(config); const node = anedya.newNode(client, nodeId); -; +; ``` > `tokenId`, `token`, and `nodeId` come from your Anedya account/device setup β€” see the [Frontend SDK docs](https://www.npmjs.com/package/@anedyasystems/anedya-frontend-sdk) for details on obtaining these and on other `node`/`client` methods (fetching historical data, live streaming, key-value store, etc.) beyond what these widgets use directly. @@ -86,12 +89,12 @@ const node = anedya.newNode(client, nodeId); ## Widgets -### CardWidget +### AnedyaCard A single-value display widget β€” shows the latest reading, a title, and a last-updated label. ```jsx - +``` + +If both a `node`/`variable` fetch *and* a `value` prop are present, the fetched value takes over once it arrives β€” `value` acts as the initial/fallback reading until then. + +`onDataChange` reflects live fetched data only β€” it does not fire based on the manual `value` prop. --- #### The styling model -`CardWidget` is **entirely class-based** β€” every visual choice is a CSS class string, not a style property. This is deliberate: card widgets are commonly styled with Tailwind, and classes compose and override far more predictably than inline styles do once you're combining a theme, a per-instance override, and a conditional rule all on the same element. +`AnedyaCard` is **entirely class-based** β€” every visual choice is a CSS class string, not a style property. This is deliberate: card widgets are commonly styled with Tailwind, and classes compose and override far more predictably than inline styles do once you're combining a theme, a per-instance override, and a conditional rule all on the same element. Every part of the card is a named **slot**: @@ -131,7 +148,7 @@ These look similar but do genuinely different things: | `className` | plain string | only the outermost container element | the ordinary React convention every component supports | ```jsx - + // or - // built-in preset, or "light" (default) + // built-in preset, or "light" (default) ``` --- @@ -172,7 +189,7 @@ const emeraldTheme = { You can freely use Tailwind's responsive prefixes inside `styles`: ```tsx - { if (!data) return; @@ -230,7 +247,7 @@ Returning `undefined` (or nothing) clears any previous overrides and restores th Rendering happens in layers. -1. The props you pass to `` +1. The props you pass to `` 2. Any temporary overrides returned from `onDataChange` 3. Theme resolution (`"light"`, `"dark"`, or a custom `WidgetTheme`) 4. Per-slot class resolution @@ -249,12 +266,12 @@ Later layers win whenever two Tailwind utilities conflict. Conflicts are resolve --- -### GaugeWidget +### AnedyaGauge A radial arc gauge β€” shows a single value as a filled arc with an optional needle, min/max tick marks, and a last-updated label. ```jsx - + ``` If both a `node`/`variable` fetch *and* a `value` prop are present, the fetched value takes over once it arrives β€” `value` acts as the initial/fallback reading until then. @@ -291,7 +309,7 @@ If both a `node`/`variable` fetch *and* a `value` prop are present, the fetched #### Slots & styling -Like `CardWidget`, every part of the gauge is a named **slot**, and the same `styles` (per-slot) / `className` (outer container only) system applies: +Like `AnedyaCard`, every part of the gauge is a named **slot**, and the same `styles` (per-slot) / `className` (outer container only) system applies: ```ts type GaugeSlot = @@ -301,7 +319,7 @@ type GaugeSlot = ``` ```jsx -` object: +`theme` works exactly as it does for `AnedyaCard` β€” a preset name, or a custom `WidgetTheme` object: ```jsx const emeraldGaugeTheme = { @@ -330,9 +348,9 @@ const emeraldGaugeTheme = { }, }; - + // or - // built-in preset, or "light" (default) + // built-in preset, or "light" (default) ``` --- @@ -342,7 +360,7 @@ const emeraldGaugeTheme = { `arc` controls the shape of the gauge itself: ```jsx - + ``` | Prop | Type | Default | Description | @@ -387,9 +405,9 @@ A default `startAngle`/`endAngle` of `-90`/`90` draws the classic bottom half-ci `color` sets the fill of the value arc β€” a single color, or 2+ colors for a gradient: ```jsx - + - + // renders a left-to-right gradient across the filled portion of the arc ``` @@ -400,7 +418,7 @@ If omitted, the bar falls back to the theme's `bar` slot color via `currentColor #### Needle configuration ```jsx - + ``` --- @@ -444,7 +462,7 @@ Setting `needle={{ show: false }}` turns the gauge into a donut-style indicator `tick` draws radial marks (and optional labels) around the arc between `min` and `max`. Off by default: ```jsx - 11 marks (0,10,...,100) @@ -482,7 +500,7 @@ Enabling ticks reserves extra space inside the widget for the line + gaps + labe `animation` controls the transition when the value (and, if enabled, the needle) moves to a new reading: ```jsx - + ``` | Prop | Type | Default | Description | @@ -497,12 +515,12 @@ With `animation.show: false`, both the bar and needle snap directly to the new v #### `onDataChange` β€” data-driven rendering -`onDataChange` works the same way it does on `CardWidget` (see [`onDataChange` under CardWidget](#ondatachange--data-driven-rendering)) β€” it's called with the latest fetched reading and a `meta` object, and can return a partial set of props (including `styles`) that temporarily override the gauge's own props: +`onDataChange` works the same way it does on `AnedyaCard` (see [`onDataChange` under AnedyaCard](#ondatachange--data-driven-rendering)) β€” it's called with the latest fetched reading and a `meta` object, and can return a partial set of props (including `styles`) that temporarily override the gauge's own props: **Example 1 – change many props based on value ranges** ```tsx - { @@ -573,9 +591,9 @@ The only difference from Card is the data shape passed in β€” `GaugeData` (`{ va #### How props are resolved -Rendering follows the same layered order as `CardWidget`: +Rendering follows the same layered order as `AnedyaCard`: -1. The props you pass to `` +1. The props you pass to `` 2. Any temporary overrides returned from `onDataChange` 3. Theme resolution (`"light"`, `"dark"`, or a custom `WidgetTheme`) 4. Per-slot class resolution @@ -594,7 +612,7 @@ Later layers win whenever two Tailwind utilities conflict, resolved with `twMerg ## Common -The sections below apply to every widget in this SDK. Where behavior is identical, only the shared explanation is given once; each subsection includes an example for both `CardWidget` and `GaugeWidget`. +The sections below apply to every widget in this SDK. Where behavior is identical, only the shared explanation is given once; each subsection includes an example for both `AnedyaCard` and `AnedyaGauge`. ### Formatting vs rendering @@ -609,23 +627,23 @@ The sections below apply to every widget in this SDK. Where behavior is identica For values that need unit-aware scaling (bytes, durations, lengths, etc.), pass a `format` preset instead of manually computing a unit string: ```tsx -// CardWidget - +// AnedyaCard + // renders "512" + "MB" β€” auto-scaled, no manual unit needed - + // renders "2d 4h 12m" - + // renders "1.25" + "km" ``` ```tsx -// GaugeWidget - +// AnedyaGauge + // renders "512" + "MB" on the value, and (if tick.show is on) scaled units on tick labels too - + // renders "2d 4h 12m" ``` @@ -655,33 +673,33 @@ Available presets: - **`locale`** β€” force a specific number format instead of relying on the visitor's browser/OS locale. Useful for a dashboard serving a specific region, or an app with its own explicit language setting: ```tsx - + // "1,23,456" (Indian digit grouping) instead of "123,456" - + // "123.456" (German uses "." as the thousands separator, "," as the decimal point) ``` - **`formatOptions`** β€” control decimal places in the *scaled* output (not the raw value). Useful when the default rounding is too coarse for scientific/financial data, or you want whole numbers for a cleaner dashboard look: ```tsx - + // "512.34" + "MB" β€” more decimal places than the default - + // "512" + "MB" β€” whole number, no decimals ``` - **`binary`** β€” *(`bytes` preset only)* choose between 1000-based and 1024-based scaling. These genuinely produce different numbers for the same raw byte count, so picking the wrong one can make a value look incorrect even though the math is technically right for the mode you're in: ```tsx - + // raw 1048576 -> "1" + "MiB" β€” matches how OS file managers/RAM usage are usually reported - + // raw 1048576 -> "1.05" + "MB" β€” matches how storage manufacturers/network specs are usually reported ``` As a rule of thumb: use `binary: true` for memory/RAM/file-size-on-disk readings, and the default (decimal) for network throughput or storage capacity marketing figures. -**`format` takes over the `unit` slot entirely.** When set, the preset determines its own unit per value (e.g. switching from `"KB"` to `"MB"` as a byte count grows) β€” the `unit` prop is ignored while `format` is active. On `GaugeWidget`, if `tick.labelFormat` isn't set, enabled tick labels also reuse the active `format` preset, so the value and the tick ring stay unit-consistent. +**`format` takes over the `unit` slot entirely.** When set, the preset determines its own unit per value (e.g. switching from `"KB"` to `"MB"` as a byte count grows) β€” the `unit` prop is ignored while `format` is active. On `AnedyaGauge`, if `tick.labelFormat` isn't set, enabled tick labels also reuse the active `format` preset, so the value and the tick ring stay unit-consistent. > **Presets don't validate that they match your data's actual meaning** β€” they only know how to scale a raw number. Applying `format="length"` to a Celsius reading, for example, will scale it as if it were meters and display a plausible-looking but semantically wrong unit. Only use a preset that matches what the underlying value actually represents. @@ -690,22 +708,22 @@ Available presets: `formatValue` always wins if provided β€” it's a full custom formatting function and bypasses `format`/`decimalPlaces` entirely: ```tsx -// CardWidget - `${v.toFixed(2)} % RH`} labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} /> ``` ```tsx -// GaugeWidget - `${v.toFixed(1)}%`} labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} /> ``` -> Long `formatValue` output (e.g. `"56.00 % RH"`) may wrap onto a second line at small widths β€” the value slot wraps rather than overflowing. On `CardWidget` this interacts with a fixed `height` β€” see [Sizing](#sizing) below. On `GaugeWidget`, the value block sits below (or centered over, in needle-less mode) the arc and wraps the same way within the available space. +> Long `formatValue` output (e.g. `"56.00 % RH"`) may wrap onto a second line at small widths β€” the value slot wraps rather than overflowing. On `AnedyaCard` this interacts with a fixed `height` β€” see [Sizing](#sizing) below. On `AnedyaGauge`, the value block sits below (or centered over, in needle-less mode) the arc and wraps the same way within the available space. --- @@ -716,11 +734,11 @@ By default, the label under the value shows a fixed clock time (`"Updated 14:32: #### `timezone` β€” override auto-detection ```tsx - + // commonProps = { node, variable: "humidity" } // shows the timestamp converted to Eastern time, regardless of the visitor's own browser timezone - + // commonProps = { node, variable: "humidity" } // shows the timestamp converted to Indian Standard Time ``` @@ -729,20 +747,20 @@ If omitted, the widget uses `Intl.DateTimeFormat().resolvedOptions().timeZone` `timezone` affects the `time`, `date`, and `datetime` label presets. It has no effect on `relative` (a time difference is timezone-independent) or `iso` (ISO 8601 output is always UTC by definition). -> **`GaugeWidget` in manual mode:** if you're using `value` without a `node` (see [Manual vs live values](#manual-vs-live-values)), there's no fetched timestamp to show. The label falls back to the moment the widget first mounted, so it still renders something meaningful instead of disappearing. ++> **In manual `value` mode** (either widget, no `node` provided): there's no fetched timestamp to show. The label falls back to the moment the widget first mounted, so it still renders something meaningful instead of disappearing. #### `labelFormat` β€” named presets ```tsx - + // commonProps = { node, variable: "humidity" } // "5 minutes ago" instead of "Updated 14:32:10" - + // commonProps = { node, variable: "humidity" } // "Updated 7/24/2026" - + // commonProps = { node, variable: "humidity" } // "5 minutes ago" instead of "Updated 14:32:10" ``` @@ -763,7 +781,7 @@ Available presets: ```tsx // AM/PM, 12-hour - { const d = new Date(ts < 1e12 ? ts * 1000 : ts); return `Updated ${d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", hour12: true })}`; @@ -772,12 +790,12 @@ Available presets: // "Updated 2:32 PM" // Combining relative time with custom text -import { relativeTime } from "public-widget-sdk/formatters"; +import { relativeTime } from "anedya-widgets-react/formatters"; - `Last synced ${relativeTime(ts)}`} />; + `Last synced ${relativeTime(ts)}`} />; // "Last synced 5 minutes ago" - `Last synced ${relativeTime(ts)}`} />; + `Last synced ${relativeTime(ts)}`} />; // "Last synced 5 minutes ago" ``` @@ -798,7 +816,7 @@ Every widget distinguishes between three outcomes of a fetch, each rendered diff Both `error` and `empty` are real slots, so they pick up theme colors automatically and can be restyled the same way as any other slot: ```tsx - - (

@@ -833,7 +851,7 @@ For full control beyond just restyling text, `renderError` and `renderEmpty` let renderEmpty={() => β€” no reading yet β€”} /> - (
@@ -854,7 +872,7 @@ For full control beyond just restyling text, `renderError` and `renderEmpty` let `onDataChange` receives a second argument describing which state just occurred, so you can react to errors or empty data the same way you already react to values: ```tsx - { if (meta.kind === "error") { @@ -870,7 +888,7 @@ For full control beyond just restyling text, `renderError` and `renderEmpty` let }} /> - { if (meta.kind === "error") { @@ -900,7 +918,7 @@ This is backwards compatible β€” existing `onDataChange={(data) => {...}}` callb The formatting helpers used internally are also available as a standalone import, for composing into your own `labelText`/`formatValue` functions β€” usable with either widget: ```tsx -import { relativeTime } from "public-widget-sdk/formatters"; +import { relativeTime } from "anedya-widgets-react/formatters"; ``` | Export | Signature | Description | @@ -911,12 +929,12 @@ import { relativeTime } from "public-widget-sdk/formatters"; ### Sizing -#### CardWidget +#### AnedyaCard `width` / `height` / `minWidth` / `maxWidth` are plain props, applied as inline styles on the container β€” independent of the whole `styles`/theme system: ```jsx - + ``` ##### `height` has two distinct modes @@ -930,19 +948,19 @@ Whether you pass `height` changes how the card behaves β€” this is intentional, ```jsx // Auto-height: card grows to fit content, whatever that content turns out to be - + // Fixed-height: card is exactly 300px tall; content that doesn't fit is clipped - + ``` If you're using a `formatValue` that can produce long strings, either don't pass a fixed `height` (let the card grow to fit), or pass a `height` generous enough for the wrapped text at your chosen `width`. -#### GaugeWidget +#### AnedyaGauge ```jsx - - // shorthand: sets width AND height to the same value (a square gauge) + + // shorthand: sets width AND height to the same value (a square gauge) ``` `size` takes priority over `width`/`height` when both are set. Without `size` or `height`, the gauge fills its container's width and derives a proportional height automatically (unless `aspectRatio` is set). @@ -978,7 +996,7 @@ By default the following properties scale automatically: **When `height` is omitted**, scaling responds to the container's **width only** (`cqw`). -**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size container renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. For the `GaugeWidget`, the arc radius and thickness are also computed from the available container size, so they resize automatically. +**When `height` is passed**, scaling responds to **both width and height** (`cqw` + `cqh`) β€” a taller fixed-size container renders bigger text/gaps than a shorter one at the same width, in addition to width's usual effect. For the `AnedyaGauge`, the arc radius and thickness are also computed from the available container size, so they resize automatically. A widget inside a narrow dashboard column will use smaller typography than the same widget rendered full-width, even on the same screen β€” this behavior is built in and needs no configuration. @@ -987,15 +1005,15 @@ A widget inside a narrow dashboard column will use smaller typography than the s If you provide your own font-size utility for a slot, you're opting out of the default responsive sizing for that slot. ```tsx -// CardWidget - -// GaugeWidget - **GaugeWidget note:** the arc's radius itself is handled separately from these CSS variables (it's a geometry calculation, not a font size) β€” it auto-fits to whatever space is left after padding and, if enabled, tick-mark space is subtracted, capped by `arc.radius` when you set one explicitly. +> **AnedyaGauge note:** the arc's radius itself is handled separately from these CSS variables (it's a geometry calculation, not a font size) β€” it auto-fits to whatever space is left after padding and, if enabled, tick-mark space is subtracted, capped by `arc.radius` when you set one explicitly. --- ### Loading & error states -#### CardWidget +#### AnedyaCard While the initial fetch is in flight, the card renders **skeleton loaders** in place of the value and label β€” pulsing placeholder blocks sized to match each slot's current font-size variable (`var(--anedya-card-value-size)` / `var(--anedya-card-label-size)`), so the skeleton scales along with the card exactly like the real content would. @@ -1018,7 +1036,7 @@ If the fetch fails or no data is available, the card renders the error message t Neither state currently accepts style overrides via `styles` β€” flag it if you need to customize their appearance. -#### GaugeWidget +#### AnedyaGauge While the initial fetch is in flight, the gauge renders the same kind of pulsing skeleton blocks in place of the value and label (sized against `var(--anedya-gauge-value-size)` / `var(--anedya-gauge-label-size)`), and the arc/needle themselves render at reduced opacity rather than disappearing, so the gauge's shape stays visible while data loads. @@ -1028,15 +1046,16 @@ If the fetch fails or no data is available, the error message (or `renderError`/ ### Other props -#### CardWidget +#### AnedyaCard | Prop | Type | Description | | --------------- | -------- | ------------------------------------------------------------------------------------ | | `title` | `string` | Card title. Default: `"Latest Value"` | +| `value` | `number` | Manual/controlled value. Used as the initial value, or the only value if no `node` is given | | `unit` | `string` | Unit suffix shown next to the value | | `decimalPlaces` | `number` | Decimal places for the displayed value (used only if `formatValue` isn't provided) | -#### GaugeWidget +#### AnedyaGauge | Prop | Type | Description | | --------------- | --------- | -------------------------------------------------------------------------------------------------- | @@ -1056,7 +1075,7 @@ This SDK ships pre-compiled CSS alongside its JavaScript β€” you don't need Tail **Import the stylesheet once**, anywhere in your app's entry point (e.g. `main.tsx`, `App.tsx`, or your global styles file): ```jsx -import "public-widget-sdk/styles.css"; +import "anedya-widgets-react/styles.css"; ``` That's the entire integration on your end. No `content` glob changes to your `tailwind.config`, no build coordination, nothing else required β€” every widget in this SDK will render fully styled as soon as this import is present. diff --git a/dist/index.d.mts b/dist/index.d.mts deleted file mode 100644 index f4fd538d..00000000 --- a/dist/index.d.mts +++ /dev/null @@ -1,99 +0,0 @@ -import { a as LabelFormatPreset, n as FormatOptions, o as SlotClassNames, r as FormatPreset, t as AnedyaWidgetBaseProps } from "./common-DoLkuLwh.mjs"; -//#region src/components/CardWidget.d.ts -type CardSlot = "container" | "title" | "value" | "unit" | "label" | "error" | "empty"; -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -interface CardData { - value: number; - timestamp: number; -} -/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ -interface CardDataMeta { - kind: "success" | "error" | "empty"; - /** Present only when kind === "error". */ - error?: string; -} -type CardWidgetUpdate = Partial>; -interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - decimalPlaces?: number; - /** - * Full custom formatting function β€” receives the raw fetched value, - * returns the exact string to display. - * - * Takes precedence over both `format` and `decimalPlaces`. - */ - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - styles?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * styles: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: (data: CardData | null, meta: CardDataMeta) => CardWidgetUpdate | void; - /** - * Named formatting preset for common unit types β€” auto-scales both - * the displayed number and its unit (e.g. `"bytes"` turns `500000` - * into `"500"` + `"KB"`). - * - * When set, this overrides the `unit` prop β€” the preset determines - * its own unit per value. - * - * Ignored if `formatValue` is also provided. - */ - format?: FormatPreset; - /** Options for the active `format` preset β€” e.g. `{ formatOptions: 2, locale: "en-IN" }`. */ - formatOptions?: FormatOptions; - /** - * Named preset for the last-updated label's format. Ignored if - * `labelText` is also provided (which always takes precedence). - * Defaults to `"time"`, matching the widget's previous fixed behavior. - */ - labelFormat?: LabelFormatPreset; - /** Custom render for the error state. Return JSX to fully replace the default error text. */ - renderError?: (error: string) => React.ReactNode; - /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ - renderEmpty?: () => React.ReactNode; - /** - * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when - * formatting the last-updated label. Defaults to the browser's - * auto-detected timezone if omitted. - */ - timezone?: string; -} -declare function CardWidget({ node, variable, title, unit, decimalPlaces, formatValue, labelText, styles, onDataChange, theme, className, width, height, minWidth, maxWidth, format, formatOptions, labelFormat, timezone, renderError, renderEmpty }: CardWidgetProps): React.JSX.Element; -//#endregion -export { CardWidget }; \ No newline at end of file diff --git a/examples/application-example/README.md b/examples/application-example/README.md index e16d995e..57ebb48c 100644 --- a/examples/application-example/README.md +++ b/examples/application-example/README.md @@ -1,18 +1,193 @@ -# React + Vite +# Anedya Widgets Example -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +A minimal React application demonstrating how to use the **Anedya Widgets SDK** with the **Anedya Frontend SDK**. -Currently, two official plugins are available: +This project shows how to authenticate with Anedya, create a client and node, and display live IoT data using the provided widgets. It also demonstrates rendering widgets with manually supplied values, making it a simple reference for integrating the SDK into your own dashboards and applications. -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) +--- -## React Compiler +## Prerequisites -The React Compiler is enabled on this template. See [this documentation](https://react.dev/learn/react-compiler) for more information. +Before running the example, you'll need: -Note: This will impact Vite dev & build performances. +- Node.js 18 or later +- An Anedya account +- A valid **Token ID** +- A valid **Token** +- A **Node ID** for a device -## Expanding the ESLint configuration +--- -If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. +## Installation + +Clone the repository and install the project dependencies. + +```bash +npm install +``` + +--- + +## Configuration + +Open `src/App.tsx` and replace the placeholder credentials with your own: + +```tsx +const tokenId = "YOUR_TOKEN_ID"; +const token = "YOUR_TOKEN"; +const nodeId = "YOUR_NODE_ID"; +``` + +The example creates an Anedya client and node that are passed directly to the widgets: + +```tsx +import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; + +const anedya = new Anedya(); + +const config = anedya.newConfig(tokenId, token); +const client = anedya.newClient(config); +const node = anedya.newNode(client, nodeId); +``` + +--- + +## Running the example + +Start the development server: + +```bash +npm run dev +``` + +Open the URL displayed in your terminal (typically `http://localhost:5173`). + +--- + +# Using the widgets + +## Live data + +To display live values from Anedya, provide a `node` and `variable`. + +### Card + +```tsx + +``` + +### Gauge + +```tsx + +``` + +--- + +## Manual values + +Widgets can also be rendered without connecting to Anedya by providing a `value`. + +### Card + +```tsx + +``` + +### Gauge + +```tsx + +``` + +When both `value` and `node`/`variable` are provided, the manual value is used initially until live data is received. + +--- + +# Required props + +The widgets support two operating modes. + +## Live data mode + +| Prop | Description | +|------|-------------| +| `node` | Anedya node instance | +| `variable` | Variable name to fetch | + +Both props are required when displaying live data. + +--- + +## Manual value mode + +| Prop | Description | +|------|-------------| +| `value` | Value to display | + +When `value` is supplied, `node` and `variable` are not required. + +--- + +# Common optional props + +Both widgets support the following optional props: + +| Prop | Purpose | +|------|---------| +| `title` | Widget title | +| `unit` | Unit displayed beside the value | +| `theme` | Built-in or custom theme | +| `styles` | Style individual widget slots | +| `className` | Style the outer container | +| `width` | Widget width | +| `height` | Widget height | +| `minWidth` | Minimum width | +| `maxWidth` | Maximum width | +| `format` | Built-in value formatter | +| `formatOptions` | Formatting options | +| `formatValue` | Custom value formatter | +| `labelFormat` | Built-in timestamp formatter | +| `labelText` | Custom timestamp text | +| `timezone` | Timezone used for timestamps | +| `renderError` | Custom error state | +| `renderEmpty` | Custom empty state | +| `onDataChange` | React to incoming data and dynamically update widget props | + +--- + +# Gauge-specific props + +`AnedyaGauge` also supports additional configuration options: + +- `min` +- `max` +- `arc` +- `track` +- `needle` +- `tick` +- `animation` +- `color` + +The example application demonstrates many of these options and can be used as a reference when configuring your own gauges. + +--- + +# Project purpose + +This application is intended as a reference implementation for the Anedya Widgets SDK. It demonstrates the recommended setup, authentication flow, and common widget configurations, making it a useful starting point for building custom dashboards and IoT applications. \ No newline at end of file diff --git a/examples/application-example/package-lock.json b/examples/application-example/package-lock.json index 53d391c0..cddce2ca 100644 --- a/examples/application-example/package-lock.json +++ b/examples/application-example/package-lock.json @@ -11,7 +11,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^9.2.0", - "public-widget-sdk": "file:../../", + "anedya-widgets-react": "file:../../", "react": "^19.2.4", "react-dom": "^19.2.4" }, @@ -33,7 +33,6 @@ } }, "../..": { - "name": "public-widget-sdk", "version": "5.5.0", "license": "ISC", "dependencies": { @@ -90,7 +89,6 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -300,6 +298,40 @@ "node": ">=6.9.0" } }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -375,7 +407,6 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -419,7 +450,6 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -966,6 +996,7 @@ "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/Boshen" } @@ -993,6 +1024,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1010,6 +1042,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1027,6 +1060,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1044,6 +1078,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1061,6 +1096,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1078,6 +1114,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1095,6 +1132,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1112,6 +1150,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1129,6 +1168,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1146,6 +1186,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1163,6 +1204,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1180,6 +1222,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1194,6 +1237,7 @@ "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", @@ -1203,6 +1247,31 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@rolldown/binding-win32-arm64-msvc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.0.tgz", @@ -1216,6 +1285,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1233,6 +1303,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1243,7 +1314,6 @@ "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "picomatch": "^4.0.4" }, @@ -1851,7 +1921,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1907,7 +1976,6 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1942,6 +2010,10 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/anedya-widgets-react": { + "resolved": "../..", + "link": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1986,7 +2058,6 @@ "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -2042,7 +2113,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.44", "caniuse-lite": "^1.0.30001806", @@ -2304,7 +2374,6 @@ "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3478,10 +3547,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/public-widget-sdk": { - "resolved": "../..", - "link": true - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -3497,7 +3562,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3507,7 +3571,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3810,7 +3873,6 @@ "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.5", @@ -4259,7 +4321,6 @@ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/examples/application-example/package.json b/examples/application-example/package.json index 69feefbc..9289e573 100644 --- a/examples/application-example/package.json +++ b/examples/application-example/package.json @@ -13,7 +13,7 @@ "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", "@mui/material": "^9.2.0", - "public-widget-sdk": "file:../../", + "anedya-widgets-react": "file:../../", "react": "^19.2.4", "react-dom": "^19.2.4" }, diff --git a/examples/application-example/src/App.jsx b/examples/application-example/src/App.jsx index 52b3c89a..a706b854 100644 --- a/examples/application-example/src/App.jsx +++ b/examples/application-example/src/App.jsx @@ -1,8 +1,8 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "../../../src"; -import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "public-widget-sdk/styles.css"; +import { AnedyaCard } from "anedya-widgets-react"; +import { AnedyaGauge } from "anedya-widgets-react"; +import "anedya-widgets-react/styles.css"; import "./index.css"; // This demo has its own Tailwind build (see vite.config.js + src/index.css), @@ -11,9 +11,9 @@ import "./index.css"; // precompiled stylesheet only covers its built-in default classes, not // arbitrary classes a consumer passes in. -const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; -const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; -const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; +const tokenId = "YOUR-TOKEN-ID"; +const token = "YOUR-TOKEN"; +const nodeId = "YOUR-NODE-ID"; const anedya = new Anedya(); const config = anedya.newConfig(tokenId, token); @@ -30,7 +30,7 @@ const commonProps = { node, variable: "humidity" }; // light/dark preset. // ============================================================ -/** A custom CardWidget theme. */ +/** A custom AnedyaCard theme. */ const emeraldCardTheme = { styles: { container: "bg-emerald-50 border-emerald-200", @@ -41,7 +41,7 @@ const emeraldCardTheme = { }; /** - * A custom GaugeWidget theme. + * A custom AnedyaGauge theme. * * Note the two different color formats in play: * - `container`/`title`/`value`/`label` are Tailwind classes, since those @@ -76,28 +76,28 @@ export default function App() { }} > {/* ================================================================ - * SECTION 1 β€” CardWidget + * SECTION 1 β€” AnedyaCard * ================================================================ */} {/* ---------------------------------------------------------------- * 1.1 Default appearance β€” no theme, no styles, no formatting * props. Every built-in fallback in one place. * ---------------------------------------------------------------- */} - + {/* ---------------------------------------------------------------- * 1.2 theme β€” a reusable, shareable WidgetTheme object. Same * effect across every widget instance that uses it. Built-in * preset names ("light" / "dark") also work directly. * ---------------------------------------------------------------- */} - - + {/* ---------------------------------------------------------------- * 1.3 styles vs className β€” the distinction that matters most: @@ -116,7 +116,7 @@ export default function App() { * precompiled stylesheet only covers its own built-in classes. * This demo has its own Tailwind build for exactly this reason. * ---------------------------------------------------------------- */} - `${v.toFixed(2)} % RH`} @@ -148,7 +148,7 @@ export default function App() { * fully custom JSX via renderError/renderEmpty. See README "Error * & empty states" for the full behavior and styles.error/empty. * ---------------------------------------------------------------- */} - + {/* ================================================================ - * SECTION 2 β€” GaugeWidget + * SECTION 2 β€” AnedyaGauge * ================================================================ */} {/* ---------------------------------------------------------------- * 2.1 Default appearance β€” live data, no theme/styling overrides. * ---------------------------------------------------------------- */} - + {/* ---------------------------------------------------------------- * 2.2 Manual value mode β€” pass `value` directly instead of `node`/ * `variable` for a static/controlled gauge (e.g. driven by your * own app state rather than live Anedya data). * ---------------------------------------------------------------- */} - + {/* ---------------------------------------------------------------- * 2.3 Full arc/track/needle/color/tick configuration, plus a * custom theme. Demonstrates most visual knobs at once. * ---------------------------------------------------------------- */} - {/* ---------------------------------------------------------------- - * 2.4 onDataChange β€” same pattern as CardWidget: conditional + * 2.4 onDataChange β€” same pattern as AnedyaCard: conditional * overrides (title, color, needle color, track color, animation * speed) driven by the raw fetched value. * ---------------------------------------------------------------- */} - {/* ---------------------------------------------------------------- - * 2.7 Error & empty states β€” identical mechanism to CardWidget. + * 2.7 Error & empty states β€” identical mechanism to AnedyaCard. * ---------------------------------------------------------------- */} - ( @@ -324,9 +324,9 @@ export default function App() { /> {/* ---------------------------------------------------------------- - * 2.8 timezone β€” same as CardWidget's. + * 2.8 timezone β€” same as AnedyaCard's. * ---------------------------------------------------------------- */} - +
); } \ No newline at end of file diff --git a/examples/application-example/src/Test.tsx b/examples/application-example/src/Test.tsx deleted file mode 100644 index da9c986f..00000000 --- a/examples/application-example/src/Test.tsx +++ /dev/null @@ -1,1335 +0,0 @@ -// import React from "react"; -// import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -// import { CardWidget } from "../../../src"; -// import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -// import "../../../dist/styles.css"; - -// import { relativeTime } from "../../../src/helpers/formatters"; -// const tokenId = "sdaIC9xpHKdPQpWXPtOlG1Pl"; -// const token = -// "eMYc82DiKX2oO9TgXylCCeyugok8MDOY65XMTRDLdsh2ENHOi0Tyv3RmfCuLQ6kb"; -// const nodeId = "019e8d46-e895-713f-b763-6969b36e37a4"; - -// const anedya = new Anedya(); -// const config = anedya.newConfig(tokenId, token); -// const client = anedya.newClient(config); -// const node = anedya.newNode(client, nodeId); - -// /** -// * A reusable theme, shareable across every CardWidget instance in your -// * app. Only specify the slots you actually want to change from the -// * built-in default β€” anything omitted falls back to lightTheme/darkTheme. -// */ -// const emeraldTheme = { -// classNames: { -// container: "bg-emerald-50 border-emerald-200", -// title: "text-emerald-700", -// value: "text-emerald-900", -// label: "text-emerald-500", -// }, -// }; - - -// const commonProps = { node, variable: "humidity" }; - -// export default function App() { -// return ( - -//
- -// `Last synced ${relativeTime(ts)}`} - -// /> - - -// {/* ============================================================ -// * 2. theme β€” a reusable, shareable WidgetTheme object. Same -// * effect across every widget instance that uses it. -// * ============================================================ */} -// - -// {/* Built-in preset names also work directly: */} -// - -// {/* ============================================================ -// * 3. styles vs className β€” THE distinction to understand: -// * -// * - `styles` (plural, an OBJECT): per-SLOT overrides. -// * Keys are "container" | "title" | "value" | "unit" | "label" -// * β€” lets you reach INSIDE the widget and style individual -// * pieces independently. -// * -// * - `className` (singular, a STRING): the ordinary React -// * convention β€” one class applied ONLY to the widget's -// * outermost container element, same as you'd pass to any -// * other component. It's merged (via twMerge) with whatever -// * styles.container already resolved to, not a -// * replacement for it. -// * -// * This example uses BOTH at once so the difference is visible: -// * className adds a shadow to the outer box, styles.value/ -// * styles.title style two INNER pieces independently. -// * ============================================================ */} -// - -// {/* ============================================================ -// * 4. Plain CSS classes β€” styles works with ANY class source, -// * not just Tailwind. These reference plain hand-written CSS -// * classes (e.g. defined in a .css file this app already imports). -// * ============================================================ */} -// {/* */} - -// {/* ============================================================ -// * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` -// * work exactly as they do anywhere else in your app, because -// * styles just forwards whatever string you write straight -// * to `className`. This widget does NOT have its own custom -// * breakpoint system β€” these prefixes are compiled by YOUR -// * project's Tailwind config and respond to the BROWSER VIEWPORT, -// * same as native Tailwind everywhere else. If your own -// * tailwind.config.js customizes `theme.screens`, these prefixes -// * automatically follow that customization too β€” nothing to -// * configure on the widget's side. -// * ============================================================ */} -// {/* */} - -// {/* ============================================================ -// * 6. formatValue / labelText β€” simple formatting hooks, distinct -// * from styling. formatValue controls the displayed number's -// * text; labelText controls the caption under it. -// * ============================================================ */} -// {/* `${v.toFixed(2)} % RH`} -// labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - -// /> */} - -// {/* ============================================================ -// * 7. onStyleChange β€” conditional class overrides driven by the -// * RAW fetched data ({ value, timestamp }), always applied on top -// * of everything else (theme, styles, className). -// * ============================================================ */} -// {/* { -// if (!data) return; - -// if (data.value > 80) { -// return { -// title: "High Humidity", -// theme: "dark", -// styles: { -// value: "text-red-500" -// } -// }; -// } - -// return { -// title: "Humidity", -// theme: "light" -// }; -// }} - -// /> */} - -// {/* ============================================================ -// * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, -// * applied as inline styles on the container, independent of the -// * whole styles/theme system. -// * ============================================================ */} -// {/* */} - - -// {/* { -// // "Hello"; -// // }, -// // }} -// // labels={{ -// // show: true, -// // position: "outside", -// // }} -// // scale={{ -// // minLabel: "Hello", -// // maxLabel: "World", -// // }} -// // ticks={{ -// // show: true, -// // count: 10, -// // position: "outside", -// // length: 10, -// // labels: true, -// // }} -// animation={{ -// duration: 4000, -// easing: "easeElasticOut", // easeCubicOut, easeElasticOut -// }} -// // tooltip={{ -// // show:false, -// // }} -// // classNames={{ -// // title: "text-white", -// // tickLabel: "text-white text-lg", -// // label: "text-red", -// // value: "text-white", -// // }} -// theme="dark" -// /> */} - -// - -// - -// -// style={{ -// backgroundColor: "#1e1e2f", -// borderRadius: "16px", -// padding: "10px", -// }} -// // 'styles' affects specific internal SVG/HTML slots via Tailwind classes -// styles={{ -// container: "border border-gray-700", // merges with outer wrapper -// title: "text-purple-400 text-xs uppercase tracking-wider", -// value: "text-white text-2xl font-mono", -// unit: "text-gray-400 text-sm", -// label: "text-gray-500 text-[10px]", -// bar: "fill-gradient-to-r from-purple-500 to-pink-500", // if using Tailwind gradients -// needle: "stroke-pink-400 stroke-2", -// needleCap: "fill-pink-400", -// }} -// /> - -// - -// - -// - -// {/* // 1. Show a custom static text */} -// "Last reading"} // Always shows "Last reading" -// /> - -// {/* // 2. Format the timestamp exactly how you want */} -// -// `Updated at ${new Date(timestamp).toLocaleString("en-US", { -// hour: "2-digit", -// minute: "2-digit", -// second: "2-digit", -// })}` -// } -// // Output: "Updated at 02:30:45 PM" -// /> - -// {/* // 3. Show relative time with custom wording */} -// { -// const diff = Math.floor((Date.now() - timestamp) / 60000); -// if (diff < 1) return "Just now"; -// if (diff < 60) return `${diff} min ago`; -// return `${Math.floor(diff / 60)} hours ago`; -// }} -// /> - -// {/* // 4. Hide the label entirely (return null or empty string) */} -// null} // No label shown -// /> -//
-// ); -// } - -{ - /* -//create react app -//link public-widget-sdk -//npm run dev -//send this file tp yash to copy paste */ -} - - - -// import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -// import * as d3 from "d3"; -// import { twMerge } from "tailwind-merge"; -// import { AnedyaWidgetBaseProps } from "../../common"; -// import { SlotClassNames, WidgetTheme } from "../../types/root"; -// import { -// GaugeAnimationConfig, -// GaugeArcConfig, -// GaugeBarSpec, -// GaugeColor, -// GaugeLabelsConfig, -// GaugeNeedleConfig, -// GaugeNeedleLabelConfig, -// GaugeScaleConfig, -// GaugeSegment, -// GaugeSlot, -// GaugeThreshold, -// GaugeTicksConfig, -// GaugeTooltipConfig, -// GaugeTrackConfig, -// GaugeValueLabelConfig, -// GaugeVariant, -// } from "../../types/gauge"; -// import { -// DEFAULT_GAUGE_THEME, -// GAUGE_DEFAULT_CLASSES, -// gaugeDarkTheme, -// gaugeLightTheme, -// } from "../../themes/gaugeTheme"; -// import { useResizeObserver } from "../../hooks/useResizeObserver"; - -// export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { -// variant?: GaugeVariant; -// /** Used before live data arrives, or standalone in dummy-data mode. */ -// value?: number; -// min?: number; -// max?: number; -// size?: number; -// responsive?: boolean; - -// arc?: GaugeArcConfig; -// track?: GaugeTrackConfig; -// fillMode?: "progress" | "solid"; -// /** Single-bar fill color (progress/needle/segmented variants). Pass an array of 2+ colors for a gradient. */ -// color?: GaugeColor; -// bars?: GaugeBarSpec[]; - -// needle?: GaugeNeedleConfig; -// labels?: GaugeLabelsConfig; -// valueLabel?: GaugeValueLabelConfig; -// needleLabel?: GaugeNeedleLabelConfig; -// scale?: GaugeScaleConfig; -// ticks?: GaugeTicksConfig; -// segments?: GaugeSegment[]; -// thresholds?: GaugeThreshold[]; -// animation?: GaugeAnimationConfig; -// tooltip?: GaugeTooltipConfig; - -// classNames?: SlotClassNames; -// style?: React.CSSProperties; - -// onClick?: (value: number) => void; -// onHover?: (value: number | null) => void; -// onValueChange?: (value: number) => void; -// } - -// const DEG2RAD = Math.PI / 180; - -// const DEFAULT_ARC: Required> = { -// startAngle: -90, -// endAngle: 90, -// cornerRadius: 0, -// gap: 6, -// }; - -// const DEFAULT_ANIMATION: Required = { -// duration: 750, -// easing: "easeCubicOut", -// }; - -// function resolveEase(name: string) { -// return (d3 as any)[name] ?? d3.easeCubicOut; -// } - -// function needlePixelLength( -// length: GaugeNeedleConfig["length"], -// radius: number -// ) { -// if (typeof length === "number") return length; -// switch (length) { -// case "short": -// return radius * 0.55; -// case "full": -// return radius * 0.95; -// case "medium": -// default: -// return radius * 0.75; -// } -// } - -// /** Builds a needle shape as an SVG path/element string, pointing "up" (-y) from the origin. */ -// function needleShape( -// type: NonNullable, -// length: number, -// width: number -// ) { -// const w = width; -// switch (type) { -// case "line": -// return { -// tag: "line", -// attrs: { -// x1: 0, -// y1: 0, -// x2: 0, -// y2: -length, -// strokeWidth: w, -// strokeLinecap: "butt", -// }, -// }; -// case "rounded": -// return { -// tag: "line", -// attrs: { -// x1: 0, -// y1: 0, -// x2: 0, -// y2: -length, -// strokeWidth: w, -// strokeLinecap: "round", -// }, -// }; -// case "triangle": { -// const half = w / 2; -// return { -// tag: "polygon", -// attrs: { -// points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ -// -length * 0.15 -// }`, -// }, -// }; -// } -// case "drop": -// default: { -// const half = w / 2; -// // Teardrop: rounded base, sharp tip. -// const d = `M ${-half} 0 -// C ${-half} ${-length * 0.35}, ${-w} ${ -// -length * 0.7 -// }, 0 ${-length} -// C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 -// A ${half} ${half} 0 1 1 ${-half} 0 Z`; -// return { tag: "path", attrs: { d } }; -// } -// } -// } - -// function isGradientColor(c?: GaugeColor): c is string[] { -// return Array.isArray(c) && c.length >= 2; -// } - -// /** Ensures a with the given id/colors exists in and returns its url() reference. Reuses the def if colors are unchanged. */ -// function resolveFill( -// defs: d3.Selection, -// id: string, -// color: GaugeColor | undefined, -// fallback: string -// ): string { -// if (!color) return fallback; -// if (!isGradientColor(color)) return color; - -// let grad = defs.select(`#${id}`); -// if (grad.empty()) { -// grad = defs.append("linearGradient").attr("id", id); -// } -// grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); -// grad.selectAll("stop").remove(); -// color.forEach((c, i) => -// grad -// .append("stop") -// .attr("offset", `${(i / (color.length - 1)) * 100}%`) -// .attr("stop-color", c) -// ); -// return `url(#${id})`; -// } - -// /** Normalized (r=1) bounding box of an arc sweep, for any start/end angle β€” handles semicircle, 270Β°, full circle, custom. */ -// function getArcBounds(startDeg: number, endDeg: number) { -// const lo = Math.min(startDeg, endDeg); -// const hi = Math.max(startDeg, endDeg); -// const angles = [startDeg, endDeg]; -// for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); - -// let minX = Infinity, -// maxX = -Infinity, -// minY = Infinity, -// maxY = -Infinity; -// angles.forEach((deg) => { -// const a = deg * DEG2RAD; -// const x = Math.sin(a); -// const y = -Math.cos(a); -// minX = Math.min(minX, x); -// maxX = Math.max(maxX, x); -// minY = Math.min(minY, y); -// maxY = Math.max(maxY, y); -// }); -// return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; -// } - -// export function GaugeWidget({ -// node, -// variable, -// title, -// theme, -// className, -// style, -// width, -// height, -// minWidth = 160, -// maxWidth = 480, -// minHeight = 160, -// maxHeight = 480, -// aspectRatio, - -// variant = "progress", -// value: valueProp, -// min = 0, -// max = 100, -// size, -// responsive = true, - -// arc, -// track, -// fillMode = "progress", -// color, -// bars, - -// needle, -// labels, -// valueLabel, -// needleLabel, -// scale, -// ticks, -// segments, -// thresholds, -// animation, -// tooltip, - -// classNames = {}, -// onClick, -// onHover, -// onValueChange, -// }: GaugeWidgetProps) { -// const svgRef = useRef(null); -// const tooltipRef = useRef(null); -// const prevValueRef = useRef(min); - -// const [fetchedValue, setFetchedValue] = useState(null); -// const [hoverValue, setHoverValue] = useState(null); - -// // ---- Live data fetch (mirrors CardWidget) ---- -// useEffect(() => { -// if (!node) return; -// let mounted = true; - -// node -// .getLatestData(variable) -// .then((res: any) => { -// if (!mounted) return; -// if (res?.isSuccess && res?.isDataAvailable) { -// setFetchedValue(res.data.value); -// } -// }) -// .catch(() => { -// /* fall back to `value` prop / dummy data silently */ -// }); - -// return () => { -// mounted = false; -// }; -// }, [node, variable]); - -// const rawValue = fetchedValue ?? valueProp ?? min; -// const clampedValue = Math.min(max, Math.max(min, rawValue)); - -// useEffect(() => { -// onValueChange?.(clampedValue); -// }, [clampedValue]); // eslint-disable-line react-hooks/exhaustive-deps - -// // ---- Responsive sizing ---- -// const { ref: wrapperRef, size: dims } = useResizeObserver( -// responsive && size == null -// ); - -// // ---- Resolved config (defaults per variant) ---- -// const resolvedArc = { ...DEFAULT_ARC, ...arc }; - -// const resolvedTrack: Required = { -// show: track?.show ?? true, -// color: track?.color ?? "", -// }; - -// const needleShownByDefault = variant === "progress" || variant === "needle"; - -// const resolvedNeedle: Required> & { -// length: NonNullable; -// } = { -// show: needle?.show ?? needleShownByDefault, -// type: needle?.type ?? "rounded", -// length: needle?.length ?? "medium", -// width: needle?.width ?? 4, -// color: needle?.color ?? "", -// capRadius: needle?.capRadius ?? 6, -// animation: needle?.animation ?? true, -// }; - -// const resolvedLabels: Required = { -// show: labels?.show ?? true, -// position: labels?.position ?? "outside", -// }; - -// const resolvedValueLabel: Required< -// Omit -// > & { formatter?: (v: number) => string } = { -// show: valueLabel?.show ?? true, -// precision: valueLabel?.precision ?? 0, -// prefix: valueLabel?.prefix ?? "", -// suffix: valueLabel?.suffix ?? "", -// formatter: valueLabel?.formatter, -// }; - -// const resolvedNeedleLabel: Required< -// Omit -// > & { formatter?: (v: number) => string } = { -// show: needleLabel?.show ?? false, -// formatter: needleLabel?.formatter, -// }; - -// const resolvedTicks: Required = { -// show: ticks?.show ?? (variant === "needle" || variant === "segmented"), -// count: ticks?.count ?? 5, -// position: ticks?.position ?? "outside", -// length: ticks?.length ?? 6, -// labels: ticks?.labels ?? true, -// }; - -// const resolvedAnimation = { ...DEFAULT_ANIMATION, ...animation }; - -// const resolvedTooltip: Required = { -// show: tooltip?.show ?? true, -// }; - -// // ---- Theme + slot classes (identical precedence chain to CardWidget) ---- -// const resolvedTheme: WidgetTheme = -// theme === "dark" -// ? gaugeDarkTheme -// : theme === "light" -// ? gaugeLightTheme -// : (theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; - -// const resolveSlot = useCallback( -// (slot: GaugeSlot) => -// twMerge( -// GAUGE_DEFAULT_CLASSES[slot], -// resolvedTheme.styles[slot], -// classNames[slot] -// ), -// [resolvedTheme, classNames] -// ); - -// const boxWidth = size ?? width ?? (dims.width || 240); - -// const boxHeight = size ?? height ?? (dims.height || boxWidth * 0.62); - -// const bounds = useMemo( -// () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), -// [resolvedArc.startAngle, resolvedArc.endAngle] -// ); - -// const pad = 8; -// // Reserve room below the arc for value/needle-label/variable text so -// // the dome never gets crowded β€” bigger reserve when the value label is on. -// const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; - -// // Ticks (and their number labels) draw *outside* the arc's own radius, -// // so the radius-fit math below must shrink the arc enough to leave -// // room for them β€” otherwise tick labels get clipped by the SVG -// // viewBox, which looked like "some ticks are hidden". -// const tickOverflow = -// resolvedTicks.show && resolvedTicks.position !== "inside" -// ? resolvedTicks.length + (resolvedTicks.labels ? 26 : 8) -// : 0; -// // Scale min/max labels also draw past the arc's radius at the two ends. -// const scaleLabelOverflow = -// resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) ? 24 : 0; -// const edgeOverflow = Math.max(tickOverflow, scaleLabelOverflow); - -// const availW = boxWidth - pad * 2 - edgeOverflow * 2; -// const availH = boxHeight * (1 - textReserve) - pad * 2 - edgeOverflow; - -// const outerRadius = -// resolvedArc.radius ?? -// Math.max(24, Math.min(availW / (bounds.w || 1), availH / (bounds.h || 1))); - -// const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); - -// // Center the arc's bounding box within the available width, anchor its top at `pad`. -// const cx = -// pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; -// const cy = pad - bounds.minY * outerRadius; - -// const angleScale = useMemo( -// () => -// d3 -// .scaleLinear() -// .domain([min, max]) -// .range([ -// resolvedArc.startAngle * DEG2RAD, -// resolvedArc.endAngle * DEG2RAD, -// ]) -// .clamp(true), -// [min, max, resolvedArc.startAngle, resolvedArc.endAngle] -// ); - -// // ---- D3 draw ---- -// useEffect(() => { -// if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; - -// const svg = d3.select(svgRef.current); -// const defs = svg.select("defs"); -// const root = svg.select("g.anedya-gauge-root"); -// root.attr("transform", `translate(${cx},${cy})`); - -// const ease = resolveEase(resolvedAnimation.easing); -// const arcGen = d3 -// .arc<{ startAngle: number; endAngle: number; r: number }>() -// .innerRadius((d) => d.r - thickness) -// .outerRadius((d) => d.r) -// .cornerRadius(resolvedArc.cornerRadius) -// .startAngle((d) => d.startAngle) -// .endAngle((d) => d.endAngle); - -// const startA = resolvedArc.startAngle * DEG2RAD; -// const endA = resolvedArc.endAngle * DEG2RAD; - -// // --- Track --- -// const trackSel = root.select( -// "path.anedya-gauge-track-path" -// ); -// if (resolvedTrack.show && variant !== "multiBar") { -// trackSel -// .attr( -// "d", -// arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! -// ) -// .attr("fill", resolvedTrack.color || "currentColor") -// .attr("opacity", 1); -// } else { -// trackSel.attr("opacity", 0); -// } - -// // --- Bar (progress / solid / segmented base) --- -// const barGroup = root.select("g.anedya-gauge-bar-group"); -// barGroup.selectAll("*").remove(); - -// if (variant === "multiBar" && bars?.length) { -// const maxBars = bars.slice(0, 10); -// maxBars.forEach((bar, i) => { -// const r = outerRadius - i * (thickness + resolvedArc.gap); -// if (resolvedTrack.show) { -// barGroup -// .append("path") -// .attr("d", arcGen({ startAngle: startA, endAngle: endA, r })!) -// .attr( -// "class", -// twMerge("anedya-gauge-multibar-track", resolveSlot("track")) -// ) -// .attr("fill", resolvedTrack.color || "currentColor") -// .attr("stroke", "none"); -// } -// const valAngle = d3 -// .scaleLinear() -// .domain([min, max]) -// .range([startA, endA]) -// .clamp(true)(bar.value); - -// const barFill = resolveFill( -// defs, -// `anedya-gauge-bar-fill-${i}`, -// bar.color, -// "currentColor" -// ); - -// const path = barGroup -// .append("path") -// .attr("class", resolveSlot("bar")) -// .attr("fill", barFill) -// .attr("stroke", "none"); -// path -// .datum({ startAngle: startA, endAngle: startA, r }) -// .attr("d", arcGen as any) -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("d", function (d: any) { -// const i2 = d3.interpolate(d.endAngle, valAngle); -// return (t) => { -// d.endAngle = i2(t); -// return arcGen(d)!; -// }; -// }); -// }); -// } else if (segments?.length) { -// const scaleAngle = d3 -// .scaleLinear() -// .domain([min, max]) -// .range([startA, endA]) -// .clamp(true); -// // Half the configured gap, converted from px to radians at this radius, -// // so adjoining segments get visible separation like distinct blocks. -// const gapRad = resolvedArc.gap / 2 / outerRadius || 0; - -// const segArcGen = d3 -// .arc<{ startAngle: number; endAngle: number; r: number }>() -// .innerRadius((d) => d.r - thickness) -// .outerRadius((d) => d.r) -// .cornerRadius(resolvedArc.cornerRadius || thickness / 4) -// .startAngle((d) => d.startAngle) -// .endAngle((d) => d.endAngle); - -// segments.forEach((seg, idx) => { -// const segStart = scaleAngle(seg.from) + gapRad; -// const segEnd = scaleAngle(seg.to) - gapRad; -// if (segEnd <= segStart) return; - -// const fill = resolveFill( -// defs, -// `anedya-gauge-segment-fill-${idx}`, -// seg.color, -// "currentColor" -// ); -// barGroup -// .append("path") -// .attr("class", resolveSlot("segment")) -// .attr("fill", fill) -// .attr("stroke", "none") -// .attr( -// "d", -// segArcGen({ -// startAngle: segStart, -// endAngle: segEnd, -// r: outerRadius, -// })! -// ); -// }); -// } else { -// const valueAngle = angleScale(clampedValue); -// const barColorRaw: GaugeColor | undefined = -// color ?? -// (thresholds?.length -// ? [...thresholds] -// .sort((a, b) => a.value - b.value) -// .reduce( -// (acc, th) => (clampedValue >= th.value ? th.color : acc), -// thresholds[0].color -// ) -// : undefined); - -// const barFill = resolveFill( -// defs, -// "anedya-gauge-bar-fill", -// barColorRaw, -// "currentColor" -// ); - -// const path = barGroup -// .append("path") -// .attr("class", resolveSlot("bar")) -// .attr("fill", barFill) -// .attr("stroke", "none"); - -// const from = fillMode === "solid" ? startA : startA; -// const to = fillMode === "solid" ? endA : valueAngle; - -// path -// .datum({ -// startAngle: startA, -// endAngle: -// prevValueRef.current != null -// ? angleScale(prevValueRef.current) -// : startA, -// r: outerRadius, -// }) -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("d", function (d: any) { -// const i2 = d3.interpolate(d.endAngle, to); -// return (t) => { -// d.endAngle = i2(t); -// return arcGen({ -// startAngle: from, -// endAngle: d.endAngle, -// r: outerRadius, -// })!; -// }; -// }); -// } - -// // --- Ticks --- -// const tickGroup = root.select("g.anedya-gauge-ticks"); -// tickGroup.selectAll("*").remove(); -// if (resolvedTicks.show) { -// const count = Math.max(2, resolvedTicks.count); -// const tickR = -// resolvedTicks.position === "inside" -// ? outerRadius - thickness -// : resolvedTicks.position === "cross" -// ? outerRadius - thickness / 2 -// : outerRadius + 4; -// d3.range(count).forEach((i) => { -// const t = i / (count - 1); -// const tv = min + t * (max - min); -// const a = angleScale(tv); -// const x1 = Math.sin(a) * tickR; -// const y1 = -Math.cos(a) * tickR; -// const x2 = -// Math.sin(a) * -// (tickR + -// (resolvedTicks.position === "inside" -// ? -resolvedTicks.length -// : resolvedTicks.length)); -// const y2 = -// -Math.cos(a) * -// (tickR + -// (resolvedTicks.position === "inside" -// ? -resolvedTicks.length -// : resolvedTicks.length)); -// tickGroup -// .append("line") -// .attr("class", resolveSlot("tick")) -// .attr("stroke", "currentColor") -// .attr("x1", x1) -// .attr("y1", y1) -// .attr("x2", x2) -// .attr("y2", y2); - -// if (resolvedTicks.labels) { -// const lx = Math.sin(a) * (tickR + resolvedTicks.length + 10); -// const ly = -Math.cos(a) * (tickR + resolvedTicks.length + 10); -// tickGroup -// .append("text") -// .attr("class", resolveSlot("tickLabel")) -// .attr("x", lx) -// .attr("y", ly) -// .attr("text-anchor", "middle") -// .attr("dominant-baseline", "middle") -// .text(String(Math.round(tv))); -// } -// }); -// } -// // --- Scale min/max labels (drawn at the arc's real start/end points, -// // not floated at the container's edges) --- -// const scaleLabelGroup = root.select( -// "g.anedya-gauge-scale-labels" -// ); -// scaleLabelGroup.selectAll("*").remove(); -// if (resolvedLabels.show && (scale?.minLabel || scale?.maxLabel)) { -// const labelR = -// outerRadius + -// (resolvedTicks.show ? resolvedTicks.length + 16 : 12); - -// const drawScaleLabel = (angle: number, text: string) => { -// const x = Math.sin(angle) * labelR; -// const y = -Math.cos(angle) * labelR; -// // Anchor away from the point so the label doesn't overlap the arc: -// // labels on the left side end at x, labels on the right start at x. -// const anchor = x < -2 ? "end" : x > 2 ? "start" : "middle"; -// scaleLabelGroup -// .append("text") -// .attr("class", resolveSlot("scaleLabel")) -// .attr("x", x) -// .attr("y", y) -// .attr("text-anchor", anchor) -// .attr("dominant-baseline", "middle") -// .text(text); -// }; - -// if (scale?.minLabel) drawScaleLabel(startA, scale.minLabel); -// if (scale?.maxLabel) drawScaleLabel(endA, scale.maxLabel); -// } - -// // --- Needle --- -// const needleGroup = root.select("g.anedya-gauge-needle"); -// if (resolvedNeedle.show && variant !== "multiBar") { -// const len = needlePixelLength(resolvedNeedle.length, outerRadius); -// const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); - -// needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); -// const needleEl = needleGroup.insert( -// shape.tag as any, -// "circle.anedya-gauge-needle-cap" -// ); -// needleEl -// .attr("class", resolveSlot("needle")) -// .attr("fill", resolvedNeedle.color || "currentColor") -// .attr("stroke", resolvedNeedle.color || "currentColor"); -// Object.entries(shape.attrs).forEach(([k, v]) => -// needleEl.attr( -// k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), -// v as any -// ) -// ); - -// let cap = needleGroup.select( -// "circle.anedya-gauge-needle-cap" -// ); -// if (cap.empty()) { -// cap = needleGroup -// .append("circle") -// .attr( -// "class", -// twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) -// ); -// } -// cap -// .attr("r", resolvedNeedle.capRadius) -// .attr("fill", resolvedNeedle.color || "currentColor"); - -// const targetDeg = angleScale(clampedValue) / DEG2RAD; -// if (resolvedNeedle.animation) { -// needleGroup -// .transition() -// .duration(resolvedAnimation.duration) -// .ease(ease) -// .attrTween("transform", function () { -// const current = needleGroup.attr("data-angle") -// ? +needleGroup.attr("data-angle")! -// : startA / DEG2RAD; -// const interp = d3.interpolate(current, targetDeg); -// return (t) => { -// const a = interp(t); -// needleGroup.attr("data-angle", String(a)); -// return `rotate(${a})`; -// }; -// }); -// } else { -// needleGroup -// .attr("transform", `rotate(${targetDeg})`) -// .attr("data-angle", String(targetDeg)); -// } -// needleGroup.attr("opacity", 1); -// } else { -// needleGroup.attr("opacity", 0); -// } - -// prevValueRef.current = clampedValue; -// }, [ -// boxWidth, -// boxHeight, -// cx, -// cy, -// outerRadius, -// thickness, -// variant, -// clampedValue, -// min, -// max, -// fillMode, -// color, -// JSON.stringify(bars), -// JSON.stringify(segments), -// JSON.stringify(thresholds), -// resolvedTrack.show, -// resolvedTrack.color, -// resolvedNeedle.show, -// resolvedNeedle.type, -// resolvedNeedle.length, -// resolvedNeedle.width, -// resolvedNeedle.color, -// resolvedNeedle.capRadius, -// resolvedNeedle.animation, -// resolvedTicks.show, -// resolvedTicks.count, -// resolvedTicks.position, -// resolvedTicks.length, -// resolvedTicks.labels, -// resolvedAnimation.duration, -// resolvedAnimation.easing, -// resolveSlot, -// resolvedLabels.show, -// scale?.minLabel, -// scale?.maxLabel, -// ]); - -// // ---- Hover / tooltip / click (D3-driven, div overlay like BarChartWidget's tooltip) ---- -// const handlePointerMove = useCallback( -// (e: React.PointerEvent) => { -// if (!resolvedTooltip.show && !onHover) return; -// const rect = svgRef.current!.getBoundingClientRect(); -// const x = e.clientX - rect.left - cx; -// const y = e.clientY - rect.top - cy; -// const dist = Math.hypot(x, y); -// if (dist < outerRadius - thickness - 6 || dist > outerRadius + 6) { -// setHoverValue(null); -// onHover?.(null); -// return; -// } -// let a = Math.atan2(x, -y); -// const hv = angleScale.invert(a); -// const clamped = Math.min(max, Math.max(min, hv)); -// setHoverValue(clamped); -// onHover?.(clamped); -// if (tooltipRef.current) { -// tooltipRef.current.style.left = `${e.clientX - rect.left + 10}px`; -// tooltipRef.current.style.top = `${e.clientY - rect.top - 24}px`; -// } -// }, -// [ -// cx, -// cy, -// outerRadius, -// thickness, -// angleScale, -// min, -// max, -// onHover, -// resolvedTooltip.show, -// ] -// ); - -// const handlePointerLeave = useCallback(() => { -// setHoverValue(null); -// onHover?.(null); -// }, [onHover]); - -// const handleClick = useCallback( -// () => onClick?.(clampedValue), -// [onClick, clampedValue] -// ); - -// const formattedValue = resolvedValueLabel.formatter -// ? resolvedValueLabel.formatter(clampedValue) -// : `${resolvedValueLabel.prefix}${clampedValue.toFixed( -// resolvedValueLabel.precision -// )}${resolvedValueLabel.suffix}`; - -// const needleLabelText = resolvedNeedleLabel.formatter?.(clampedValue); - -// return ( -//
-// {title && {title}} - -// -// -// -// -// -// -// -// -// -// -// -// - -// {/* {resolvedLabels.show && (scale?.minLabel || scale?.maxLabel) && ( -//
-// {scale?.minLabel} -// {scale?.maxLabel} -//
-// )} */} - -// {resolvedValueLabel.show && ( -// {formattedValue} -// )} - -// {resolvedNeedleLabel.show && needleLabelText && ( -// {needleLabelText} -// )} - -// {variable && {variable}} - -// {resolvedTooltip.show && hoverValue != null && ( -//
-// {hoverValue.toFixed(resolvedValueLabel.precision)} -//
-// )} -//
-// ); -// } diff --git a/examples/application-example/src/assets/hero.png b/examples/application-example/src/assets/hero.png deleted file mode 100644 index cc51a3d20ad4bc961b596a6adfd686685cd84bb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44919 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 JPDHLkV1myZcL)Fg diff --git a/examples/application-example/src/assets/react.svg b/examples/application-example/src/assets/react.svg deleted file mode 100644 index 6c87de9b..00000000 --- a/examples/application-example/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/application-example/src/assets/vite.svg b/examples/application-example/src/assets/vite.svg deleted file mode 100644 index 5101b674..00000000 --- a/examples/application-example/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ -Vite diff --git a/package-lock.json b/package-lock.json index 79187fe5..64abeff3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "public-widget-sdk", + "name": "anedya-widgets-react", "version": "5.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "public-widget-sdk", + "name": "anedya-widgets-react", "version": "5.5.0", "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 23374949..bcaac123 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "public-widget-sdk", + "name": "anedya-widgets-react", "version": "5.5.0", "description": "Anedya widget SDK", "main": "dist/index.js", @@ -33,7 +33,7 @@ "repository": { "type": "git", - "url": "git@github.com:abhishreecodes/new-sdk.git" + "url": "https://github.com/anedyaio/anedya-widgets-react" }, "publishConfig": { "access": "public" diff --git a/src/common.ts b/src/common.ts index ec31ceb8..303da73a 100644 --- a/src/common.ts +++ b/src/common.ts @@ -3,19 +3,39 @@ import { BuiltInTheme, CardSlot } from "./types/card"; import { WidgetTheme } from "./types/root"; + /** * Every widget takes this shape as its base. Widget-specific props * (e.g. Card's `unit`/`decimalPlaces`, Chart's `tickCount`) extend this * rather than repeating client/node/sizing/theme plumbing per widget. * - * `node` is required directly (built by the consumer via - * `anedya.newNode(client, nodeId)`) rather than derived internally β€” - * keeps node/rate-limiting construction fully in the consumer's control, - * outside the widget. + * `node` is built by the consumer via `anedya.newNode(client, nodeId)` + * rather than derived internally β€” keeps node/rate-limiting construction + * fully in the consumer's control, outside the widget. + * + * `node` and `variable` are optional here because some widgets (Card, + * Gauge) also accept a manual `value` prop, making a live fetch optional + * for them. + * + * // Widgets WITHOUT a `value` fallback (e.g. ChartWidget): + * export interface ChartWidgetProps + * extends Omit { + * node: any; + * variable: string; + * // ...chart-specific props + * } + * + * // Widgets WITH a `value` fallback (e.g. AnedyaCard, AnedyaGauge): + * export interface AnedyaCardProps extends AnedyaWidgetBaseProps { + * value?: number; + * // node/variable inherited as-is (optional) β€” see the runtime + * // check in AnedyaCard itself for what enforces "one or the other" + * // at render time, since TypeScript alone can't express that. + * } */ export interface AnedyaWidgetBaseProps { - node: any; - variable: string; + node?: any; + variable?: string; /** Not every widget needs a range (e.g. Card shows only the latest value) β€” optional here, required by widgets that do. */ from?: number; to?: number; diff --git a/src/components/AnedyaCard.tsx b/src/components/AnedyaCard.tsx new file mode 100644 index 00000000..f59f1abd --- /dev/null +++ b/src/components/AnedyaCard.tsx @@ -0,0 +1,951 @@ +// import { useEffect, useMemo, useRef, useState } from "react"; +// import { twMerge } from "tailwind-merge"; +// import { AnedyaWidgetBaseProps } from "../common"; + +// import type { FormatOptions, FormatPreset, LabelFormatPreset } from "../common"; +// import { SlotClassNames, WidgetTheme } from "../types/root"; + +// import { +// CARD_DEFAULT_CLASSES, +// darkTheme, +// lightTheme, +// } from "../themes/defaultTheme"; +// import { FORMATTERS, LABEL_FORMATTERS } from "../helpers/formatters"; + +// export type CardSlot = +// | "container" +// | "title" +// | "value" +// | "unit" +// | "label" +// | "error" +// | "empty"; + +// /** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +// export interface CardData { +// value: number; +// timestamp: number; +// } +// /** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ +// export interface CardDataMeta { +// kind: "success" | "error" | "empty"; +// /** Present only when kind === "error". */ +// error?: string; +// } +// export type AnedyaCardUpdate = Partial< +// Omit +// >; +// export interface AnedyaCardProps extends AnedyaWidgetBaseProps { +// unit?: string; +// /** +// * A manual/custom value to display, mirroring AnedyaGauge's `value` +// * prop. If `node` is provided and a live fetch succeeds, the fetched +// * value takes precedence over this β€” `value` is used as the fallback +// * while no live data has arrived yet, or as the sole source of truth +// * in fully controlled mode when no `node` is passed at all. +// */ +// value?: number; +// /** Decimal places for the displayed value. Omit to show the raw value as-is. */ +// decimalPlaces?: number; +// /** +// * Full custom formatting function β€” receives the raw fetched value, +// * returns the exact string to display. +// * +// * Takes precedence over both `format` and `decimalPlaces`. +// */ +// formatValue?: (value: number) => string; +// /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ +// labelText?: (timestamp: number) => string; + +// /** +// * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, +// * CSS Modules, plain hand-written CSS, or any other CSS classes. +// * +// * Layers on top of the widget's active theme and built-in defaults. +// * Tailwind conflicts are resolved via `twMerge`, so later overrides +// * replace earlier utilities within the same Tailwind class group. +// */ +// styles?: SlotClassNames; +// /** +// * Called whenever the latest fetched data changes. +// * +// * Return a partial set of this widget's optional props to +// * temporarily override how it is rendered. +// * +// * Any returned props are applied until this callback is +// * called again. +// * +// * Returning `undefined` (or nothing) clears any previous +// * overrides and restores the widget's original props. +// * +// * Note: this reflects live fetched data only β€” it does not fire based +// * on the manual `value` prop, same as AnedyaGauge. +// * +// * Example: +// * +// * onDataChange={(data) => { +// * if (!data) return; +// * +// * if (data.value > 80) { +// * return { +// * title: "High Humidity", +// * theme: "dark", +// * styles: { +// * value: "text-red-500", +// * }, +// * }; +// * } +// * }} +// */ +// onDataChange?: ( +// data: CardData | null, +// meta: CardDataMeta +// ) => AnedyaCardUpdate | void; + +// /** +// * Named formatting preset for common unit types β€” auto-scales both +// * the displayed number and its unit (e.g. `"bytes"` turns `500000` +// * into `"500"` + `"KB"`). +// * +// * When set, this overrides the `unit` prop β€” the preset determines +// * its own unit per value. +// * +// * Ignored if `formatValue` is also provided. +// */ +// format?: FormatPreset; +// /** Options for the active `format` preset β€” e.g. `{ formatOptions: 2, locale: "en-IN" }`. */ +// formatOptions?: FormatOptions; +// /** +// * Named preset for the last-updated label's format. Ignored if +// * `labelText` is also provided (which always takes precedence). +// * Defaults to `"time"`, matching the widget's previous fixed behavior. +// */ +// labelFormat?: LabelFormatPreset; +// /** Custom render for the error state. Return JSX to fully replace the default error text. */ +// renderError?: (error: string) => React.ReactNode; + +// /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ +// renderEmpty?: () => React.ReactNode; +// /** +// * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when +// * formatting the last-updated label. Defaults to the browser's +// * auto-detected timezone if omitted. +// */ +// timezone?: string; +// } + +// const DEFAULT_WIDTH = 240; +// const DEFAULT_HEIGHT = 160; +// const DEFAULT_MIN_WIDTH = 180; +// const DEFAULT_MAX_WIDTH = 480; + +// export function AnedyaCard({ +// node, +// variable, +// title = "Latest Value", +// unit, +// value: valueProp, +// decimalPlaces, +// formatValue, +// labelText, +// styles = {}, +// onDataChange, +// theme, +// className, + +// width, +// height, +// minWidth = DEFAULT_MIN_WIDTH, +// maxWidth = DEFAULT_MAX_WIDTH, +// format, +// formatOptions, +// labelFormat, +// timezone, +// renderError, +// renderEmpty, +// }: AnedyaCardProps): React.JSX.Element { +// // Renamed from `value` -> `fetchedValue` specifically so the `value` +// // PROP above (the manual/custom override, mirroring AnedyaGauge) can +// // exist without colliding with this piece of internal fetch state β€” +// // same naming split AnedyaGauge already uses (fetchedValue vs. valueProp). +// const [fetchedValue, setFetchedValue] = useState(null); +// const [timestamp, setTimestamp] = useState(null); +// const [loading, setLoading] = useState(false); +// const [error, setError] = useState(null); +// const [isEmpty, setIsEmpty] = useState(false); +// // Holds the temporary prop overrides returned by onDataChange. +// // Whenever the callback returns nothing (or the condition no longer +// // matches), this resets back to {} so the widget falls back to the +// // original props it was created with. +// const [dynamicProps, setDynamicProps] = useState({}); + +// const mountedRef = useRef(false); +// const isFetchingRef = useRef(false); +// // Stable "now" fallback for manual/custom `value` mode, captured once on +// // mount β€” mirrors AnedyaGauge's manualTimestampRef, so the last-updated +// // label still has something to show when there's no live fetch. +// const manualTimestampRef = useRef(Date.now()); + +// useEffect(() => { +// if (!node) return; +// mountedRef.current = true; + +// const fetchLatest = async () => { +// if (isFetchingRef.current) return; +// isFetchingRef.current = true; +// setLoading(true); +// setError(null); + +// try { +// const res = await node.getLatestData(variable); +// if (!mountedRef.current) return; + +// if (res.isSuccess && res.isDataAvailable) { +// setFetchedValue(res.data.value); +// setTimestamp(res.data.timestamp); +// setError(null); +// setIsEmpty(false); +// } else if (res.isSuccess && !res.isDataAvailable) { +// // Fetch succeeded, but there's genuinely no data yet β€” distinct +// // from an actual error. +// setFetchedValue(null); +// setTimestamp(null); +// setError(null); +// setIsEmpty(true); +// } else { +// setFetchedValue(null); +// setError(res.error?.errorMessage ?? "Failed to fetch data"); +// setIsEmpty(false); +// } +// } catch (err: any) { +// if (!mountedRef.current) return; +// setFetchedValue(null); +// setError(err?.message ?? "Failed to fetch data"); +// setIsEmpty(false); +// } finally { +// if (mountedRef.current) { +// setLoading(false); +// isFetchingRef.current = false; +// } +// } +// }; + +// fetchLatest(); +// return () => { +// mountedRef.current = false; +// }; +// }, [node, variable]); + +// // Resolve onDataChange whenever data / error / empty status changes. +// // The callback returns temporary prop overrides which layer on top +// // of the widget's original props. Intentionally based on fetchedValue +// // only β€” the manual `value` prop never drives this callback, same as +// // AnedyaGauge's onDataChange. +// useEffect(() => { +// if (!onDataChange) { +// setDynamicProps({}); +// return; +// } + +// const data = +// fetchedValue != null && timestamp != null +// ? { value: fetchedValue, timestamp } +// : null; +// const meta: CardDataMeta = error +// ? { kind: "error", error } +// : isEmpty +// ? { kind: "empty" } +// : { kind: "success" }; +// setDynamicProps(onDataChange(data, meta) ?? {}); +// }, [fetchedValue, timestamp, error, isEmpty, onDataChange]); + +// const resolvedProps = { +// title, +// unit, +// decimalPlaces, +// formatValue, +// labelText, +// width: width ?? DEFAULT_WIDTH, +// // height: height ?? DEFAULT_HEIGHT, +// height, +// minWidth, +// maxWidth, +// className, +// theme, +// format, +// formatOptions, +// labelFormat, +// timezone, +// renderError, +// renderEmpty, +// ...dynamicProps, + +// styles: { +// ...(styles ?? {}), +// ...(dynamicProps.styles ?? {}), +// }, +// }; + +// // Live fetched data wins whenever it's available; the manual `value` +// // prop is the fallback β€” used before a live fetch resolves, or as the +// // only source of truth when no `node` is passed at all (fully +// // controlled mode). Same precedence AnedyaGauge uses for `rawValue`. +// const resolvedValue = fetchedValue ?? valueProp ?? null; + +// // In manual mode there's no `node`, so the live-fetch effect above +// // never runs and `timestamp` stays null forever β€” without this, the +// // last-updated label would just disappear whenever `value` is used on +// // its own. Falls back to the timestamp captured on mount instead. +// const effectiveTimestamp = +// timestamp ?? (valueProp != null ? manualTimestampRef.current : null); + +// const resolvedTheme: WidgetTheme = +// resolvedProps.theme === "dark" +// ? darkTheme +// : resolvedProps.theme === "light" +// ? lightTheme +// : resolvedProps.theme ?? lightTheme; + +// // Per-slot resolution, lowest to highest precedence: +// // 1. CARD_DEFAULT_CLASSES[slot] β€” built-in baseline +// // 2. resolvedTheme.styles[slot] β€” active theme's classes +// // 3. resolvedProps.styles +// // (original styles merged with any returned by onDataChange) + +// // twMerge resolves any real Tailwind conflicts between these layers +// // based on actual utility groups, not the order they're written in. +// const resolveSlot = (slot: CardSlot) => +// twMerge( +// CARD_DEFAULT_CLASSES[slot], +// resolvedTheme.styles?.[slot], +// resolvedProps.styles?.[slot] +// ); + +// const { displayValue, displayUnit } = useMemo(() => { +// if (resolvedValue == null) +// return { displayValue: null, displayUnit: resolvedProps.unit }; + +// if (resolvedProps.formatValue) { +// return { +// displayValue: resolvedProps.formatValue(resolvedValue), +// displayUnit: resolvedProps.unit, +// }; +// } + +// if (resolvedProps.format) { +// const result = FORMATTERS[resolvedProps.format]( +// resolvedValue, +// resolvedProps.formatOptions +// ); +// return { displayValue: result.value, displayUnit: result.unit }; +// } + +// if (resolvedProps.decimalPlaces != null) { +// return { +// displayValue: resolvedValue.toFixed(resolvedProps.decimalPlaces), +// displayUnit: resolvedProps.unit, +// }; +// } + +// return { displayValue: String(resolvedValue), displayUnit: resolvedProps.unit }; +// }, [ +// resolvedValue, +// resolvedProps.formatValue, +// resolvedProps.format, +// resolvedProps.formatOptions, +// resolvedProps.decimalPlaces, +// resolvedProps.unit, +// ]); + +// // Auto-detect the browser's timezone unless the consumer overrides it. +// const resolvedTimezone = +// resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; +// const displayLabel = useMemo(() => { +// if (effectiveTimestamp == null) return null; + +// if (resolvedProps.labelText) return resolvedProps.labelText(effectiveTimestamp); + +// const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; +// return formatter(effectiveTimestamp, { +// locale: resolvedProps.formatOptions?.locale, +// timezone: resolvedTimezone, +// }); +// }, [ +// effectiveTimestamp, +// resolvedProps.labelText, +// resolvedProps.labelFormat, +// resolvedProps.formatOptions?.locale, +// resolvedTimezone, +// ]); +// const hasExplicitHeight = height != null || dynamicProps.height != null; + +// return ( +//
+//
+// {resolvedProps.title} + +// {loading ? ( +//
+// {/* Value Skeleton: Uses the exact font-size variable as its height */} +//
+ +// {/* Label Skeleton: Uses the exact label-size variable as its height */} +//
+//
+// ) : error ? ( +// resolvedProps.renderError ? ( +// resolvedProps.renderError(error) +// ) : ( +// {error} +// ) +// ) : isEmpty ? ( +// resolvedProps.renderEmpty ? ( +// resolvedProps.renderEmpty() +// ) : ( +// N/A +// ) +// ) : ( +// <> +// +// {displayValue} + +// {displayUnit && ( +// {displayUnit} +// )} +// +// {displayLabel && ( +// {displayLabel} +// )} +// +// )} +//
+//
+// ); +// } + +import { useEffect, useMemo, useRef, useState } from "react"; +import { twMerge } from "tailwind-merge"; +import { AnedyaWidgetBaseProps } from "../common"; + +import type { FormatOptions, FormatPreset, LabelFormatPreset } from "../common"; +import { SlotClassNames, WidgetTheme } from "../types/root"; + +import { + CARD_DEFAULT_CLASSES, + darkTheme, + lightTheme, +} from "../themes/defaultTheme"; +import { FORMATTERS, LABEL_FORMATTERS } from "../helpers/formatters"; + +export type CardSlot = + | "container" + | "title" + | "value" + | "unit" + | "label" + | "error" + | "empty"; + +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +export interface CardData { + value: number; + timestamp: number; +} +/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ +export interface CardDataMeta { + kind: "success" | "error" | "empty"; + /** Present only when kind === "error". */ + error?: string; +} +export type AnedyaCardUpdate = Partial< + Omit +>; +export interface AnedyaCardProps extends AnedyaWidgetBaseProps { + unit?: string; + /** + * A manual/custom value to display, mirroring AnedyaGauge's `value` + * prop. If `node` is provided and a live fetch succeeds, the fetched + * value takes precedence over this β€” `value` is used as the fallback + * while no live data has arrived yet, or as the sole source of truth + * in fully controlled mode when no `node` is passed at all. + */ + value?: number; + /** Decimal places for the displayed value. Omit to show the raw value as-is. */ + decimalPlaces?: number; + /** + * Full custom formatting function β€” receives the raw fetched value, + * returns the exact string to display. + * + * Takes precedence over both `format` and `decimalPlaces`. + */ + formatValue?: (value: number) => string; + /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ + labelText?: (timestamp: number) => string; + + /** + * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, + * CSS Modules, plain hand-written CSS, or any other CSS classes. + * + * Layers on top of the widget's active theme and built-in defaults. + * Tailwind conflicts are resolved via `twMerge`, so later overrides + * replace earlier utilities within the same Tailwind class group. + */ + styles?: SlotClassNames; + /** + * Called whenever the latest fetched data changes. + * + * Return a partial set of this widget's optional props to + * temporarily override how it is rendered. + * + * Any returned props are applied until this callback is + * called again. + * + * Returning `undefined` (or nothing) clears any previous + * overrides and restores the widget's original props. + * + * Note: this reflects live fetched data only β€” it does not fire based + * on the manual `value` prop, same as AnedyaGauge. + * + * Example: + * + * onDataChange={(data) => { + * if (!data) return; + * + * if (data.value > 80) { + * return { + * title: "High Humidity", + * theme: "dark", + * styles: { + * value: "text-red-500", + * }, + * }; + * } + * }} + */ + onDataChange?: ( + data: CardData | null, + meta: CardDataMeta + ) => AnedyaCardUpdate | void; + + /** + * Named formatting preset for common unit types β€” auto-scales both + * the displayed number and its unit (e.g. `"bytes"` turns `500000` + * into `"500"` + `"KB"`). + * + * When set, this overrides the `unit` prop β€” the preset determines + * its own unit per value. + * + * Ignored if `formatValue` is also provided. + */ + format?: FormatPreset; + /** Options for the active `format` preset β€” e.g. `{ formatOptions: 2, locale: "en-IN" }`. */ + formatOptions?: FormatOptions; + /** + * Named preset for the last-updated label's format. Ignored if + * `labelText` is also provided (which always takes precedence). + * Defaults to `"time"`, matching the widget's previous fixed behavior. + */ + labelFormat?: LabelFormatPreset; + /** Custom render for the error state. Return JSX to fully replace the default error text. */ + renderError?: (error: string) => React.ReactNode; + + /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ + renderEmpty?: () => React.ReactNode; + /** + * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when + * formatting the last-updated label. Defaults to the browser's + * auto-detected timezone if omitted. + */ + timezone?: string; +} + +const DEFAULT_WIDTH = 240; +const DEFAULT_HEIGHT = 160; +const DEFAULT_MIN_WIDTH = 180; +const DEFAULT_MAX_WIDTH = 480; + +export function AnedyaCard({ + node, + variable, + title = "Latest Value", + unit, + value: valueProp, + decimalPlaces, + formatValue, + labelText, + styles = {}, + onDataChange, + theme, + className, + + width, + height, + minWidth = DEFAULT_MIN_WIDTH, + maxWidth = DEFAULT_MAX_WIDTH, + format, + formatOptions, + labelFormat, + timezone, + renderError, + renderEmpty, +}: AnedyaCardProps): React.JSX.Element { + // Runtime invariant β€” TypeScript alone can't express "node+variable OR + // value, but not neither" across two independent optional props (see + // the comment on AnedyaWidgetBaseProps in common.ts for why node/ + // variable are optional at the type level in the first place). This + // runs before any hooks below, so it's a stable guard clause: either + // this instance always throws on every render, or never does β€” it + // doesn't flip mid-lifecycle, so it can't violate the rules of hooks. + if (!node && valueProp == null) { + throw new Error( + "[AnedyaCard] Provide either `node` (with `variable`) for live data, or a manual `value` prop for a controlled card β€” neither was given." + ); + } + if (node && !variable) { + throw new Error( + "[AnedyaCard] `variable` is required whenever `node` is provided." + ); + } + + // Renamed from `value` -> `fetchedValue` specifically so the `value` + // PROP above (the manual/custom override, mirroring AnedyaGauge) can + // exist without colliding with this piece of internal fetch state β€” + // same naming split AnedyaGauge already uses (fetchedValue vs. valueProp). + const [fetchedValue, setFetchedValue] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [isEmpty, setIsEmpty] = useState(false); + // Holds the temporary prop overrides returned by onDataChange. + // Whenever the callback returns nothing (or the condition no longer + // matches), this resets back to {} so the widget falls back to the + // original props it was created with. + const [dynamicProps, setDynamicProps] = useState({}); + + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + // Stable "now" fallback for manual/custom `value` mode, captured once on + // mount β€” mirrors AnedyaGauge's manualTimestampRef, so the last-updated + // label still has something to show when there's no live fetch. + const manualTimestampRef = useRef(Date.now()); + + useEffect(() => { + if (!node) return; + mountedRef.current = true; + + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + + try { + // `variable!` β€” TS still sees this as `string | undefined` since + // it's typed optional on the shared base props, but the runtime + // invariant check above guarantees it's set whenever we get this + // far (the effect itself also bails out early if `!node`). + const res = await node.getLatestData(variable!); + if (!mountedRef.current) return; + + if (res.isSuccess && res.isDataAvailable) { + setFetchedValue(res.data.value); + setTimestamp(res.data.timestamp); + setError(null); + setIsEmpty(false); + } else if (res.isSuccess && !res.isDataAvailable) { + // Fetch succeeded, but there's genuinely no data yet β€” distinct + // from an actual error. + setFetchedValue(null); + setTimestamp(null); + setError(null); + setIsEmpty(true); + } else { + setFetchedValue(null); + setError(res.error?.errorMessage ?? "Failed to fetch data"); + setIsEmpty(false); + } + } catch (err: any) { + if (!mountedRef.current) return; + setFetchedValue(null); + setError(err?.message ?? "Failed to fetch data"); + setIsEmpty(false); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + + // Resolve onDataChange whenever data / error / empty status changes. + // The callback returns temporary prop overrides which layer on top + // of the widget's original props. Intentionally based on fetchedValue + // only β€” the manual `value` prop never drives this callback, same as + // AnedyaGauge's onDataChange. + useEffect(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + + const data = + fetchedValue != null && timestamp != null + ? { value: fetchedValue, timestamp } + : null; + const meta: CardDataMeta = error + ? { kind: "error", error } + : isEmpty + ? { kind: "empty" } + : { kind: "success" }; + setDynamicProps(onDataChange(data, meta) ?? {}); + }, [fetchedValue, timestamp, error, isEmpty, onDataChange]); + + const resolvedProps = { + title, + unit, + decimalPlaces, + formatValue, + labelText, + width: width ?? DEFAULT_WIDTH, + // height: height ?? DEFAULT_HEIGHT, + height, + minWidth, + maxWidth, + className, + theme, + format, + formatOptions, + labelFormat, + timezone, + renderError, + renderEmpty, + ...dynamicProps, + + styles: { + ...(styles ?? {}), + ...(dynamicProps.styles ?? {}), + }, + }; + + // Live fetched data wins whenever it's available; the manual `value` + // prop is the fallback β€” used before a live fetch resolves, or as the + // only source of truth when no `node` is passed at all (fully + // controlled mode). Same precedence AnedyaGauge uses for `rawValue`. + const resolvedValue = fetchedValue ?? valueProp ?? null; + + // In manual mode there's no `node`, so the live-fetch effect above + // never runs and `timestamp` stays null forever β€” without this, the + // last-updated label would just disappear whenever `value` is used on + // its own. Falls back to the timestamp captured on mount instead. + const effectiveTimestamp = + timestamp ?? (valueProp != null ? manualTimestampRef.current : null); + + const resolvedTheme: WidgetTheme = + resolvedProps.theme === "dark" + ? darkTheme + : resolvedProps.theme === "light" + ? lightTheme + : resolvedProps.theme ?? lightTheme; + + // Per-slot resolution, lowest to highest precedence: + // 1. CARD_DEFAULT_CLASSES[slot] β€” built-in baseline + // 2. resolvedTheme.styles[slot] β€” active theme's classes + // 3. resolvedProps.styles + // (original styles merged with any returned by onDataChange) + + // twMerge resolves any real Tailwind conflicts between these layers + // based on actual utility groups, not the order they're written in. + const resolveSlot = (slot: CardSlot) => + twMerge( + CARD_DEFAULT_CLASSES[slot], + resolvedTheme.styles?.[slot], + resolvedProps.styles?.[slot] + ); + + const { displayValue, displayUnit } = useMemo(() => { + if (resolvedValue == null) + return { displayValue: null, displayUnit: resolvedProps.unit }; + + if (resolvedProps.formatValue) { + return { + displayValue: resolvedProps.formatValue(resolvedValue), + displayUnit: resolvedProps.unit, + }; + } + + if (resolvedProps.format) { + const result = FORMATTERS[resolvedProps.format]( + resolvedValue, + resolvedProps.formatOptions + ); + return { displayValue: result.value, displayUnit: result.unit }; + } + + if (resolvedProps.decimalPlaces != null) { + return { + displayValue: resolvedValue.toFixed(resolvedProps.decimalPlaces), + displayUnit: resolvedProps.unit, + }; + } + + return { displayValue: String(resolvedValue), displayUnit: resolvedProps.unit }; + }, [ + resolvedValue, + resolvedProps.formatValue, + resolvedProps.format, + resolvedProps.formatOptions, + resolvedProps.decimalPlaces, + resolvedProps.unit, + ]); + + // Auto-detect the browser's timezone unless the consumer overrides it. + const resolvedTimezone = + resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + const displayLabel = useMemo(() => { + if (effectiveTimestamp == null) return null; + + if (resolvedProps.labelText) return resolvedProps.labelText(effectiveTimestamp); + + const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; + return formatter(effectiveTimestamp, { + locale: resolvedProps.formatOptions?.locale, + timezone: resolvedTimezone, + }); + }, [ + effectiveTimestamp, + resolvedProps.labelText, + resolvedProps.labelFormat, + resolvedProps.formatOptions?.locale, + resolvedTimezone, + ]); + const hasExplicitHeight = height != null || dynamicProps.height != null; + + return ( +
+
+ {resolvedProps.title} + + {loading ? ( +
+ {/* Value Skeleton: Uses the exact font-size variable as its height */} +
+ + {/* Label Skeleton: Uses the exact label-size variable as its height */} +
+
+ ) : error ? ( + resolvedProps.renderError ? ( + resolvedProps.renderError(error) + ) : ( + {error} + ) + ) : isEmpty ? ( + resolvedProps.renderEmpty ? ( + resolvedProps.renderEmpty() + ) : ( + N/A + ) + ) : ( + <> + + {displayValue} + + {displayUnit && ( + {displayUnit} + )} + + {displayLabel && ( + {displayLabel} + )} + + )} +
+
+ ); +} \ No newline at end of file diff --git a/src/components/CardWidget.tsx b/src/components/CardWidget.tsx deleted file mode 100644 index 942d4596..00000000 --- a/src/components/CardWidget.tsx +++ /dev/null @@ -1,426 +0,0 @@ -import { useEffect, useMemo, useRef, useState } from "react"; -import { twMerge } from "tailwind-merge"; -import { AnedyaWidgetBaseProps } from "../common"; - -import type { FormatOptions, FormatPreset, LabelFormatPreset } from "../common"; -import { SlotClassNames, WidgetTheme } from "../types/root"; - -import { - CARD_DEFAULT_CLASSES, - darkTheme, - lightTheme, -} from "../themes/defaultTheme"; -import { FORMATTERS, LABEL_FORMATTERS } from "../helpers/formatters"; - -export type CardSlot = - | "container" - | "title" - | "value" - | "unit" - | "label" - | "error" - | "empty"; - -/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ -export interface CardData { - value: number; - timestamp: number; -} -/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ -export interface CardDataMeta { - kind: "success" | "error" | "empty"; - /** Present only when kind === "error". */ - error?: string; -} -export type CardWidgetUpdate = Partial< - Omit ->; -export interface CardWidgetProps extends AnedyaWidgetBaseProps { - unit?: string; - /** Decimal places for the displayed value. Omit to show the raw value as-is. */ - decimalPlaces?: number; - /** - * Full custom formatting function β€” receives the raw fetched value, - * returns the exact string to display. - * - * Takes precedence over both `format` and `decimalPlaces`. - */ - formatValue?: (value: number) => string; - /** Text shown under the value, e.g. a last-updated label β€” pass a function to compute it from the latest timestamp. */ - labelText?: (timestamp: number) => string; - - /** - * Per-slot CSS class overrides β€” Tailwind, a shadcn-generated class, - * CSS Modules, plain hand-written CSS, or any other CSS classes. - * - * Layers on top of the widget's active theme and built-in defaults. - * Tailwind conflicts are resolved via `twMerge`, so later overrides - * replace earlier utilities within the same Tailwind class group. - */ - styles?: SlotClassNames; - /** - * Called whenever the latest fetched data changes. - * - * Return a partial set of this widget's optional props to - * temporarily override how it is rendered. - * - * Any returned props are applied until this callback is - * called again. - * - * Returning `undefined` (or nothing) clears any previous - * overrides and restores the widget's original props. - * - * Example: - * - * onDataChange={(data) => { - * if (!data) return; - * - * if (data.value > 80) { - * return { - * title: "High Humidity", - * theme: "dark", - * styles: { - * value: "text-red-500", - * }, - * }; - * } - * }} - */ - onDataChange?: ( - data: CardData | null, - meta: CardDataMeta - ) => CardWidgetUpdate | void; - - /** - * Named formatting preset for common unit types β€” auto-scales both - * the displayed number and its unit (e.g. `"bytes"` turns `500000` - * into `"500"` + `"KB"`). - * - * When set, this overrides the `unit` prop β€” the preset determines - * its own unit per value. - * - * Ignored if `formatValue` is also provided. - */ - format?: FormatPreset; - /** Options for the active `format` preset β€” e.g. `{ formatOptions: 2, locale: "en-IN" }`. */ - formatOptions?: FormatOptions; - /** - * Named preset for the last-updated label's format. Ignored if - * `labelText` is also provided (which always takes precedence). - * Defaults to `"time"`, matching the widget's previous fixed behavior. - */ - labelFormat?: LabelFormatPreset; - /** Custom render for the error state. Return JSX to fully replace the default error text. */ - renderError?: (error: string) => React.ReactNode; - - /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ - renderEmpty?: () => React.ReactNode; - /** - * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when - * formatting the last-updated label. Defaults to the browser's - * auto-detected timezone if omitted. - */ - timezone?: string; -} - -const DEFAULT_WIDTH = 240; -const DEFAULT_HEIGHT = 160; -const DEFAULT_MIN_WIDTH = 180; -const DEFAULT_MAX_WIDTH = 480; - -export function CardWidget({ - node, - variable, - title = "Latest Value", - unit, - decimalPlaces, - formatValue, - labelText, - styles = {}, - onDataChange, - theme, - className, - - width, - height, - minWidth = DEFAULT_MIN_WIDTH, - maxWidth = DEFAULT_MAX_WIDTH, - format, - formatOptions, - labelFormat, - timezone, - renderError, - renderEmpty, -}: CardWidgetProps): React.JSX.Element { - const [value, setValue] = useState(null); - const [timestamp, setTimestamp] = useState(null); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [isEmpty, setIsEmpty] = useState(false); - // Holds the temporary prop overrides returned by onDataChange. - // Whenever the callback returns nothing (or the condition no longer - // matches), this resets back to {} so the widget falls back to the - // original props it was created with. - const [dynamicProps, setDynamicProps] = useState({}); - - const mountedRef = useRef(false); - const isFetchingRef = useRef(false); - - useEffect(() => { - if (!node) return; - mountedRef.current = true; - - const fetchLatest = async () => { - if (isFetchingRef.current) return; - isFetchingRef.current = true; - setLoading(true); - setError(null); - - try { - const res = await node.getLatestData(variable); - if (!mountedRef.current) return; - - if (res.isSuccess && res.isDataAvailable) { - setValue(res.data.value); - setTimestamp(res.data.timestamp); - setError(null); - setIsEmpty(false); - } else if (res.isSuccess && !res.isDataAvailable) { - // Fetch succeeded, but there's genuinely no data yet β€” distinct - // from an actual error. - setValue(null); - setTimestamp(null); - setError(null); - setIsEmpty(true); - } else { - setValue(null); - setError(res.error?.errorMessage ?? "Failed to fetch data"); - setIsEmpty(false); - } - } catch (err: any) { - if (!mountedRef.current) return; - setValue(null); - setError(err?.message ?? "Failed to fetch data"); - setIsEmpty(false); - } finally { - if (mountedRef.current) { - setLoading(false); - isFetchingRef.current = false; - } - } - }; - - fetchLatest(); - return () => { - mountedRef.current = false; - }; - }, [node, variable]); - - // Resolve onDataChange whenever data / error / empty status changes. - // The callback returns temporary prop overrides which layer on top - // of the widget's original props. - useEffect(() => { - if (!onDataChange) { - setDynamicProps({}); - return; - } - - const data = - value != null && timestamp != null ? { value, timestamp } : null; - const meta: CardDataMeta = error - ? { kind: "error", error } - : isEmpty - ? { kind: "empty" } - : { kind: "success" }; - setDynamicProps(onDataChange(data, meta) ?? {}); - }, [value, timestamp, error, isEmpty, onDataChange]); - const resolvedProps = { - title, - unit, - decimalPlaces, - formatValue, - labelText, - width: width ?? DEFAULT_WIDTH, - // height: height ?? DEFAULT_HEIGHT, - height, - minWidth, - maxWidth, - className, - theme, - format, - formatOptions, - labelFormat, - timezone, - renderError, - renderEmpty, - ...dynamicProps, - - styles: { - ...(styles ?? {}), - ...(dynamicProps.styles ?? {}), - }, - }; - - const resolvedTheme: WidgetTheme = - resolvedProps.theme === "dark" - ? darkTheme - : resolvedProps.theme === "light" - ? lightTheme - : resolvedProps.theme ?? lightTheme; - - // Per-slot resolution, lowest to highest precedence: - // 1. CARD_DEFAULT_CLASSES[slot] β€” built-in baseline - // 2. resolvedTheme.styles[slot] β€” active theme's classes - // 3. resolvedProps.styles - // (original styles merged with any returned by onDataChange) - - // twMerge resolves any real Tailwind conflicts between these layers - // based on actual utility groups, not the order they're written in. - const resolveSlot = (slot: CardSlot) => - twMerge( - CARD_DEFAULT_CLASSES[slot], - resolvedTheme.styles?.[slot], - resolvedProps.styles?.[slot] - ); - - const { displayValue, displayUnit } = useMemo(() => { - if (value == null) - return { displayValue: null, displayUnit: resolvedProps.unit }; - - if (resolvedProps.formatValue) { - return { - displayValue: resolvedProps.formatValue(value), - displayUnit: resolvedProps.unit, - }; - } - - if (resolvedProps.format) { - const result = FORMATTERS[resolvedProps.format]( - value, - resolvedProps.formatOptions - ); - return { displayValue: result.value, displayUnit: result.unit }; - } - - if (resolvedProps.decimalPlaces != null) { - return { - displayValue: value.toFixed(resolvedProps.decimalPlaces), - displayUnit: resolvedProps.unit, - }; - } - - return { displayValue: String(value), displayUnit: resolvedProps.unit }; - }, [ - value, - resolvedProps.formatValue, - resolvedProps.format, - resolvedProps.formatOptions, - resolvedProps.decimalPlaces, - resolvedProps.unit, - ]); - - // Auto-detect the browser's timezone unless the consumer overrides it. - const resolvedTimezone = - resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; - const displayLabel = useMemo(() => { - if (timestamp == null) return null; - - if (resolvedProps.labelText) return resolvedProps.labelText(timestamp); - - const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; - return formatter(timestamp, { - locale: resolvedProps.formatOptions?.locale, - timezone: resolvedTimezone, - }); - }, [ - timestamp, - resolvedProps.labelText, - resolvedProps.labelFormat, - resolvedProps.formatOptions?.locale, - resolvedTimezone, - ]); - const hasExplicitHeight = height != null || dynamicProps.height != null; - - return ( -
-
- {resolvedProps.title} - - {loading ? ( -
- {/* Value Skeleton: Uses the exact font-size variable as its height */} -
- - {/* Label Skeleton: Uses the exact label-size variable as its height */} -
-
- ) : error ? ( - resolvedProps.renderError ? ( - resolvedProps.renderError(error) - ) : ( - {error} - ) - ) : isEmpty ? ( - resolvedProps.renderEmpty ? ( - resolvedProps.renderEmpty() - ) : ( - N/A - ) - ) : ( - <> - - {displayValue} - - {displayUnit && ( - {displayUnit} - )} - - {displayLabel && ( - {displayLabel} - )} - - )} -
-
- ); -} diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/AnedyaGauge.tsx similarity index 95% rename from src/components/GaugeChart/GaugeChartWidget.tsx rename to src/components/GaugeChart/AnedyaGauge.tsx index f81c2fa8..70da564d 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/AnedyaGauge.tsx @@ -1,4 +1,4 @@ -// GaugeWidget.tsx +// AnedyaGauge.tsx import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import * as d3 from "d3"; @@ -43,11 +43,11 @@ export interface GaugeDataMeta { error?: string; } -export type GaugeWidgetUpdate = Partial< - Omit +export type AnedyaGaugeUpdate = Partial< + Omit >; -export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { +export interface AnedyaGaugeProps extends AnedyaWidgetBaseProps { value?: number; min?: number; max?: number; @@ -89,7 +89,7 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { onDataChange?: ( data: GaugeData | null, meta: GaugeDataMeta - ) => GaugeWidgetUpdate | void; + ) => AnedyaGaugeUpdate | void; /** Custom render for the error state. Return JSX to fully replace the default error text. */ renderError?: (error: string) => React.ReactNode; @@ -270,7 +270,7 @@ function getArcBounds(startDeg: number, endDeg: number) { return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; } -export function GaugeWidget({ +export function AnedyaGauge({ node, variable, title = "Latest Value", @@ -308,7 +308,25 @@ export function GaugeWidget({ onDataChange, renderError, renderEmpty, -}: GaugeWidgetProps) { +}: AnedyaGaugeProps) : React.JSX.Element{ + // Runtime invariant β€” identical rule to AnedyaCard: TypeScript alone + // can't express "node+variable OR value, but not neither" across two + // independent optional props (see the comment on AnedyaWidgetBaseProps + // in common.ts for why node/variable are optional at the type level in + // the first place). Runs before any hooks below, so it's a stable + // guard clause β€” either this instance always throws on every render, + // or never does, so it can't violate the rules of hooks. + if (!node && valueProp == null) { + throw new Error( + "[AnedyaGauge] Provide either `node` (with `variable`) for live data, or a manual `value` prop for a controlled gauge β€” neither was given." + ); + } + if (node && !variable) { + throw new Error( + "[AnedyaGauge] `variable` is required whenever `node` is provided." + ); + } + const svgRef = useRef(null); // REQUIREMENT 2: stable "now" fallback for manual/custom `value` mode, // captured once on mount (not recomputed every render). @@ -320,12 +338,12 @@ export function GaugeWidget({ const [error, setError] = useState(null); const [isEmpty, setIsEmpty] = useState(false); - const [dynamicProps, setDynamicProps] = useState({}); + const [dynamicProps, setDynamicProps] = useState({}); const mountedRef = useRef(false); const isFetchingRef = useRef(false); - // ---- Live data fetch (mirrors CardWidget, plus timestamp) ---- + // ---- Live data fetch (mirrors AnedyaCard, plus timestamp) ---- useEffect(() => { if (!node) return; mountedRef.current = true; @@ -337,7 +355,11 @@ export function GaugeWidget({ setError(null); try { - const res = await node.getLatestData(variable); + // `variable!` β€” TS still sees this as `string | undefined` since + // it's typed optional on the shared base props, but the runtime + // invariant check above guarantees it's set whenever we get this + // far (the effect itself also bails out early if `!node`). + const res = await node.getLatestData(variable!); if (!mountedRef.current) return; if (res.isSuccess && res.isDataAvailable) { @@ -376,7 +398,7 @@ export function GaugeWidget({ }; }, [node, variable]); - // ---- onDataChange resolution (identical pattern to CardWidget) ---- + // ---- onDataChange resolution (identical pattern to AnedyaCard) ---- useEffect(() => { if (!onDataChange) { setDynamicProps({}); @@ -556,7 +578,7 @@ export function GaugeWidget({ ] ); - // ---- Value + unit formatting (same precedence as CardWidget) ---- + // ---- Value + unit formatting (same precedence as AnedyaCard) ---- const { displayValue, displayUnit } = useMemo(() => { if (resolvedProps.formatValue) { return { @@ -1114,4 +1136,4 @@ export function GaugeWidget({
); -} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 7fa9d43a..631df722 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ -export {CardWidget} from "./components/CardWidget" +export {AnedyaCard} from "./components/AnedyaCard" +export {AnedyaGauge} from "./components/GaugeChart/AnedyaGauge" diff --git a/src/themes/defaultTheme.ts b/src/themes/defaultTheme.ts index e2f0a505..c155765a 100644 --- a/src/themes/defaultTheme.ts +++ b/src/themes/defaultTheme.ts @@ -1,4 +1,5 @@ -import { CardSlot } from "../components/CardWidget"; + +import { CardSlot } from "../components/AnedyaCard"; import { WidgetTheme } from "../types/root"; export const CARD_DEFAULT_CLASSES: Record = { From b687353f0e4d638e5e7a29981894482cbfde2b67 Mon Sep 17 00:00:00 2001 From: abhishreecodes <156026573+abhishreecodes@users.noreply.github.com> Date: Tue, 28 Jul 2026 13:53:53 +0530 Subject: [PATCH 56/66] Delete .DS_Store --- .DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 38e7e2c8ea7a0b6092e0ec96940ec99c082ff781..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKy-ve05dPeDD5688F0f@|VCu#gs<0RJ0jSy_KuVg5(mlKpZ-In(0eBBaB)+q) zHYT)UKnS5b>HOLEV_&{hxf*~OuCf6T0q9Z%TYDV75b=vPq~$F=qLDrFtHF3y7K=ut z8vZH+^6omwaDyf8g7?=yUe$d?nWodcoYK~Pc|RXTqsPxP}AJmOR>TZ*(Tg-wg&Hd}f6V`;c z=ee!P=YvzC#_A0cAiLSTi8shnOmuc&r@SPX`Bk z1t4~4w!*pGB_t>In0Txl(nB#WmFQB9zhW4dPJ8U*5|5Qbmkwi3=05&p<8LU&o=$sg z!(kGKIw}LoK*&JbEhFjwXWQ@pVUn(t0cGG{F Date: Tue, 28 Jul 2026 15:12:12 +0530 Subject: [PATCH 57/66] Added an tooltip in gauge widget --- .../GaugeChart/GaugeChartWidget.tsx | 125 ++++++++++++++++++ src/styles/base.css | 1 + src/themes/gaugeTheme.ts | 6 +- src/types/gauge.ts | 14 +- test/my-app/src/App.jsx | 36 +++-- 5 files changed, 167 insertions(+), 15 deletions(-) diff --git a/src/components/GaugeChart/GaugeChartWidget.tsx b/src/components/GaugeChart/GaugeChartWidget.tsx index f81c2fa8..7965a9e5 100644 --- a/src/components/GaugeChart/GaugeChartWidget.tsx +++ b/src/components/GaugeChart/GaugeChartWidget.tsx @@ -19,6 +19,7 @@ import { GaugeTickConfig, // NEW GaugeTrackConfig, // GaugeValueLabelConfig, + GaugeTooltipConfig, // NEW β€” tooltip config type GaugeEasing, } from "../../types/gauge"; import { @@ -64,6 +65,9 @@ export interface GaugeWidgetProps extends AnedyaWidgetBaseProps { tick?: GaugeTickConfig; animation?: GaugeAnimationConfig; + /** NEW β€” hover tooltip shown over the arc (track/bar). Defaults to `"variable: value unit"`. */ + tooltip?: GaugeTooltipConfig; + // ---- Card-parity formatting props ---- unit?: string; decimalPlaces?: number; @@ -296,6 +300,7 @@ export function GaugeWidget({ // valueLabel, tick, animation, + tooltip, // NEW unit, decimalPlaces, format, @@ -320,6 +325,15 @@ export function GaugeWidget({ const [error, setError] = useState(null); const [isEmpty, setIsEmpty] = useState(false); + // NEW β€” tooltip position/visibility, updated by pointer handlers attached + // to the track/bar SVG elements in the D3 draw effect below. + const [tooltipState, setTooltipState] = useState<{ + x: number; + y: number; + visible: boolean; + flipX: boolean; // ← add this + }>({ x: 0, y: 0, visible: false, flipX: false }); + const [dynamicProps, setDynamicProps] = useState({}); const mountedRef = useRef(false); @@ -434,6 +448,7 @@ export function GaugeWidget({ needle, animation, tick, + tooltip, // NEW unit, decimalPlaces, className, @@ -487,6 +502,14 @@ export function GaugeWidget({ ...resolvedProps.animation, }; + // NEW β€” tooltip config, defaults to shown with the built-in + // "variable: value unit" content. + const resolvedTooltip: Required> & + Pick = { + show: resolvedProps.tooltip?.show ?? true, + content: resolvedProps.tooltip?.content, + }; + // ---- REQUIREMENT 3/4: tick marks config ---- // `count` = number of INTERVALS between min/max, so count=10 with the // default min=0/max=100 draws 11 marks (0,10,20...100) β€” "10 count" per @@ -626,6 +649,28 @@ export function GaugeWidget({ resolvedTimezone, ]); + // NEW β€” default tooltip text: "variable: value unit". Custom `tooltip.content` + // receives the same data plus the raw clamped value. + const tooltipContent = useMemo(() => { + if (resolvedTooltip.content) { + return resolvedTooltip.content({ + variable, + value: clampedValue, + displayValue, + unit: displayUnit, + }); + } + return variable + ? `${variable}: ${displayValue}${displayUnit ? ` ${displayUnit}` : ""}` + : `${displayValue}${displayUnit ? ` ${displayUnit}` : ""}`; + }, [ + resolvedTooltip.content, + variable, + clampedValue, + displayValue, + displayUnit, + ]); + // ---- Geometry ---- const boxWidth = resolvedProps.size ?? resolvedProps.width ?? (dims.width || DEFAULT_WIDTH); @@ -716,6 +761,27 @@ export function GaugeWidget({ const startA = resolvedArc.startAngle * DEG2RAD; const endA = resolvedArc.endAngle * DEG2RAD; + // NEW β€” shared pointer handlers for the tooltip. Position is computed + // relative to the arc wrapper div (the tooltip's positioning parent), + // not the SVG, since the SVG's internal viewBox coordinate space can + // differ from its rendered CSS size. + const handleTooltipMove = (event: MouseEvent) => { + const wrapperEl = arcWrapperRef.current as HTMLDivElement | null; + if (!wrapperEl) return; + const rect = wrapperEl.getBoundingClientRect(); + const relX = event.clientX - rect.left; + const flipX = relX > rect.width * 0.5; + setTooltipState({ + visible: true, + x: relX, + y: event.clientY - rect.top, + flipX, + }); + }; + const handleTooltipLeave = () => { + setTooltipState((s) => (s.visible ? { ...s, visible: false } : s)); + }; + const trackSel = root.select( "path.anedya-gauge-track-path" ); @@ -731,6 +797,20 @@ export function GaugeWidget({ trackSel.attr("opacity", 0); } + // NEW β€” attach/detach tooltip listeners on the track, gated by + // resolvedTooltip.show (added to this effect's dependency array below). + if (resolvedTooltip.show) { + trackSel + .style("cursor", "pointer") + .on("mousemove", handleTooltipMove) + .on("mouseleave", handleTooltipLeave); + } else { + trackSel + .style("cursor", null) + .on("mousemove", null) + .on("mouseleave", null); + } + // ---- REQUIREMENT 3/4: tick marks + labels ---- // Ticks don't animate (they're static reference marks), so it's a // simple remove-and-redraw each time rather than the persistent-node @@ -808,6 +888,17 @@ export function GaugeWidget({ .attr("stroke", "none") .attr("opacity", loading ? 0.4 : 1); + // NEW β€” same tooltip listeners on the filled bar, so hovering the + // active portion of the arc (not just the track) also triggers it. + if (resolvedTooltip.show) { + path + .style("cursor", "pointer") + .on("mousemove", handleTooltipMove) + .on("mouseleave", handleTooltipLeave); + } else { + path.style("cursor", null).on("mousemove", null).on("mouseleave", null); + } + const currentEndAngle = path.attr("data-end-angle") ? +path.attr("data-end-angle")! : startA; @@ -914,6 +1005,15 @@ export function GaugeWidget({ } else { needleGroup.attr("opacity", 0); } + + // NEW β€” hide the tooltip immediately if the pointer leaves the SVG + // entirely (not just the track/bar shapes specifically). + if (resolvedTooltip.show) { + svg.on("mouseleave", handleTooltipLeave); + } else { + svg.on("mouseleave", null); + setTooltipState((s) => (s.visible ? { ...s, visible: false } : s)); + } }, [ boxWidth, boxHeight, @@ -948,9 +1048,11 @@ export function GaugeWidget({ resolvedTick.labelGap, resolvedTick.labelSize, resolvedTick.labelColor, + resolvedTooltip.show, // NEW tickValues, formatTickLabel, resolveSlot, + arcWrapperRef, // NEW β€” used inside handleTooltipMove ]); // const handleClick = useCallback( @@ -1073,6 +1175,29 @@ export function GaugeWidget({ {valueBlock}
)} + + {/* NEW β€” tooltip. Positioned relative to this wrapper div (which is + already `relative`), follows the pointer via tooltipState.x/y + set by the D3 mousemove handlers above, and hides on mouseleave. */} + {resolvedTooltip.show && + tooltipState.visible && + !loading && + !error && + !isEmpty && ( +
+ {tooltipContent} +
+ )}
{loading ? ( diff --git a/src/styles/base.css b/src/styles/base.css index 70c78609..e3ae50f5 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -40,6 +40,7 @@ --anedya-gauge-unit-size: clamp(1rem, 0.7rem + 1.5cqw + 1.5cqh, 3.25rem); --anedya-gauge-label-size: clamp(0.75rem, 0.5rem + 1.2cqw + 1.2cqh, 2.25rem); --anedya-gauge-tick-size: clamp(0.625rem, 0.4rem + 0.6cqw + 0.6cqh, 0.875rem); + --anedya-gauge-tooltip-size: clamp(0.6875rem, 0.45rem + 0.7cqw + 0.7cqh, 1rem); --anedya-gauge-gap: 0.25rem; /* flat 4px */ transition: padding 0.25s ease, gap 0.25s ease; diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index fec54702..a0b83bed 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -4,8 +4,7 @@ import { GaugeSlot } from "../types/gauge"; import { WidgetTheme } from "../types/root"; export const GAUGE_DEFAULT_CLASSES: Record = { - container: - "flex flex-col items-center justify-center text-center", + container: "flex flex-col items-center justify-center text-center", title: "text-[length:var(--anedya-gauge-title-size)] font-medium", unit: "text-[length:var(--anedya-gauge-unit-size)] font-medium", track: "", @@ -22,6 +21,7 @@ export const GAUGE_DEFAULT_CLASSES: Record = { tickLabel: "font-medium select-none", error: "text-sm font-medium", empty: "text-[length:var(--anedya-card-value-size)] font-bold", + tooltip: "pointer-events-none z-10 rounded-md px-2 text-[length:var(--anedya-gauge-tooltip-size)] shadow-lg whitespace-nowrap font-medium", }; export const gaugeLightTheme: WidgetTheme = { @@ -39,6 +39,7 @@ export const gaugeLightTheme: WidgetTheme = { tickLabel: "text-slate-400", error: "text-red-600", empty: "text-slate-400", + tooltip: "bg-slate-900 text-white", }, }; @@ -57,6 +58,7 @@ export const gaugeDarkTheme: WidgetTheme = { tickLabel: "text-slate-500", error: "text-red-400", empty: "text-slate-500", + tooltip: "bg-white text-slate-900", }, }; diff --git a/src/types/gauge.ts b/src/types/gauge.ts index 8c939f67..4c315105 100644 --- a/src/types/gauge.ts +++ b/src/types/gauge.ts @@ -13,7 +13,8 @@ export type GaugeSlot = | "tick" // NEW β€” tick line styling via `styles` prop | "tickLabel" // NEW β€” tick number styling via `styles` prop | "error" - | "empty"; + | "empty" + | "tooltip"; export interface GaugeArcConfig { /** Degrees, 0 = 12 o'clock, clockwise-positive. */ @@ -104,6 +105,17 @@ export interface GaugeTickConfig { labelFormat?: (value: number) => string; } +export interface GaugeTooltipConfig { + show?: boolean; + /** Full custom tooltip content. Receives the raw + formatted value, unit, and the widget's `variable` name. */ + content?: (data: { + variable: string; + value: number; + displayValue: string; + unit?: string; + }) => React.ReactNode; +} + export interface GaugeAnimationConfig { show?: boolean; duration?: number; diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx index 6377960c..16b38e1d 100644 --- a/test/my-app/src/App.jsx +++ b/test/my-app/src/App.jsx @@ -448,13 +448,15 @@ export default function App() { // {...commonProps} value={95} needle={{ - length:"full", - type:"line", + length: "full", + type: "line", // show:false }} - tick={{ - // show:true, - }} + tick={ + { + // show:true, + } + } color={[ "#ff75c3", "#ffa647", @@ -475,31 +477,41 @@ export default function App() { - - + + `πŸ“Š ${variable} β†’ ${displayValue}${unit ?? ""}`, + }} + styles={{ + tooltip:"bg-indigo-600 text-white text-sm px-3 py-1.5" + }} + />
); } From 5594f662bb5c59559475860f379dfa7424ba0a21 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 28 Jul 2026 15:34:45 +0530 Subject: [PATCH 58/66] Update README.md --- README.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac16611f..4da4a004 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ A collection of pre-built, themeable React widgets for displaying Anedya IoT dat - [Needle configuration](#needle-configuration) - [Needle-less (donut) mode](#needle-less-donut-mode) - [Tick marks](#tick-marks) + - [Tooltip](#tooltip) - [Animation configuration](#animation-configuration) - [`onDataChange` β€” data-driven rendering](#ondatachange--data-driven-rendering-1) - [How props are resolved](#how-props-are-resolved-1) @@ -297,7 +298,7 @@ Like `CardWidget`, every part of the gauge is a named **slot**, and the same `st type GaugeSlot = | "container" | "title" | "unit" | "track" | "bar" | "needle" | "needleCap" | "value" | "label" - | "tick" | "tickLabel" | "error" | "empty"; + | "tick" | "tickLabel" | "tooltip" | "error" | "empty"; ``` ```jsx @@ -327,6 +328,7 @@ const emeraldGaugeTheme = { value: "text-emerald-900", needle: "text-emerald-700", needleCap: "text-emerald-700", + tooltip: "bg-emerald-200 text-emerald-700", }, }; @@ -477,6 +479,50 @@ Enabling ticks reserves extra space inside the widget for the line + gaps + labe --- + +#### Tooltip + +`tooltip` shows a hover tooltip over the arc (both the track and the filled bar respond) β€” enabled by default. The built-in tooltip text is `"variable: value unit"`, using the **formatted** value (`displayValue` β€” after `format`/`formatValue`/`decimalPlaces` is applied), not the raw number: + +```jsx + +// hovering the arc shows: "temperature: 42.5 Β°C" +``` + +| Prop | Type | Default | Description | +| --------- | ---------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------------------------------------ | +| `show` | `boolean` | `true` | Whether hovering the arc shows a tooltip | +| `content` | `(data: { variable: string; value: number; displayValue: string; unit?: string }) => ReactNode` | β€” | Full custom tooltip content. Receives both the **raw** clamped `value` and the already-**formatted** `displayValue`/`unit`, alongside the widget's `variable` name | + +Disable it with `tooltip={{ show: false }}`, or fully replace the content with your own JSX β€” `content` gets the raw value in case you want to do your own formatting/thresholds rather than reuse `displayValue`: + +```jsx + ( +
+ {variable} + {displayValue}{unit ? ` ${unit}` : ""} + raw: {value} +
+ ), + }} +/> +``` + +The tooltip follows the pointer and flips to the opposite side automatically once the pointer crosses the horizontal midpoint of the gauge, so it never overflows off the edge of a narrow container. It's hidden automatically while the widget is in a loading, error, or empty state. + +Like every other part of the gauge, the tooltip is styleable via the `tooltip` slot in `styles` or a custom theme: + +```jsx + +``` +--- + #### Animation configuration `animation` controls the transition when the value (and, if enabled, the needle) moves to a new reading: @@ -519,6 +565,13 @@ With `animation.show: false`, both the bar and needle snap directly to the new v needle: { type: "triangle", color: "#dc2626" }, animation: { duration: 500, easing: "elasticOut" }, tick: { show: true, color: "#fca5a5", labelColor: "#f87171" }, + tooltip: { + content: ({ variable, displayValue, unit }) => ( + + ⚠ {variable}: {displayValue}{unit ? ` ${unit}` : ""} β€” critical + + ), + }, styles: { value: "text-red-500 text-4xl font-black", title: "uppercase tracking-wide", @@ -531,9 +584,10 @@ With `animation.show: false`, both the bar and needle snap directly to the new v color: ["#10b981", "#34d399"], arc: { thickness: 18 }, needle: { show: false }, + tooltip: { show: false }, // low readings aren't worth hovering for }; } - // Clear overrides for mid-range values + // Clear overrides for mid-range values β€” tooltip reverts to the default }} /> ``` From a0d0a0abf52174e24cf32d65ea93f78fb7102e61 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 28 Jul 2026 15:47:31 +0530 Subject: [PATCH 59/66] fix conflicts --- examples/index.js | 0 src/components/GaugeChart/AnedyaGauge.tsx | 1264 +++++++++++++++++++++ 2 files changed, 1264 insertions(+) create mode 100644 examples/index.js diff --git a/examples/index.js b/examples/index.js new file mode 100644 index 00000000..e69de29b diff --git a/src/components/GaugeChart/AnedyaGauge.tsx b/src/components/GaugeChart/AnedyaGauge.tsx index e69de29b..3eb0628a 100644 --- a/src/components/GaugeChart/AnedyaGauge.tsx +++ b/src/components/GaugeChart/AnedyaGauge.tsx @@ -0,0 +1,1264 @@ +// AnedyaGauge.tsx + +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import * as d3 from "d3"; +import { twMerge } from "tailwind-merge"; +import { + AnedyaWidgetBaseProps, + FormatOptions, + FormatPreset, + LabelFormatPreset, +} from "../../common"; +import { SlotClassNames, WidgetTheme } from "../../types/root"; +import { + GaugeAnimationConfig, + GaugeArcConfig, + GaugeColor, + GaugeNeedleConfig, + GaugeSlot, + GaugeTickConfig, // NEW + GaugeTrackConfig, + // GaugeValueLabelConfig, + GaugeTooltipConfig, // NEW β€” tooltip config type + GaugeEasing, +} from "../../types/gauge"; +import { + DEFAULT_GAUGE_THEME, + GAUGE_DEFAULT_CLASSES, + gaugeDarkTheme, + gaugeLightTheme, +} from "../../themes/gaugeTheme"; +import { useResizeObserver } from "../../hooks/useResizeObserver"; +import { FORMATTERS, LABEL_FORMATTERS } from "../../helpers/formatters"; + +/** The raw data this widget fetched β€” exactly what comes back from the request, not yet formatted. */ +export interface GaugeData { + value: number; + timestamp: number; +} + +/** Describes which state the widget just landed in, passed alongside `data` to `onDataChange`. */ +export interface GaugeDataMeta { + kind: "success" | "error" | "empty"; + /** Present only when kind === "error". */ + error?: string; +} + +export type AnedyaGaugeUpdate = Partial< + Omit +>; + +export interface AnedyaGaugeProps extends AnedyaWidgetBaseProps { + value?: number; + min?: number; + max?: number; + size?: number; + // responsive?: boolean; + + arc?: GaugeArcConfig; + track?: GaugeTrackConfig; + color?: GaugeColor; + + needle?: GaugeNeedleConfig; + // valueLabel?: GaugeValueLabelConfig; + /** REQUIREMENT 3/4: radial min/max tick marks drawn around the arc. */ + tick?: GaugeTickConfig; + animation?: GaugeAnimationConfig; + + /** NEW β€” hover tooltip shown over the arc (track/bar). Defaults to `"variable: value unit"`. */ + tooltip?: GaugeTooltipConfig; + + // ---- Card-parity formatting props ---- + unit?: string; + decimalPlaces?: number; + formatValue?: (value: number) => string; + format?: FormatPreset; + formatOptions?: FormatOptions; + labelText?: (timestamp: number) => string; + labelFormat?: LabelFormatPreset; + /** + * IANA timezone name (e.g. "Asia/Kolkata", "America/New_York") used when + * formatting the last-updated label. Defaults to the browser's + * auto-detected timezone if omitted. + */ + timezone?: string; + + styles?: SlotClassNames; + // style?: React.CSSProperties; + + onClick?: (value: number) => void; + // REQUIREMENT 5: onValueChange removed β€” onDataChange already lets the + // caller override *any* prop whenever new data arrives, so a separate + // value-only callback was redundant. + onDataChange?: ( + data: GaugeData | null, + meta: GaugeDataMeta + ) => AnedyaGaugeUpdate | void; + + /** Custom render for the error state. Return JSX to fully replace the default error text. */ + renderError?: (error: string) => React.ReactNode; + + /** Custom render when the fetch succeeds but no data is available. Defaults to a greyed-out "N/A". */ + renderEmpty?: () => React.ReactNode; +} + +const DEG2RAD = Math.PI / 180; + +const DEFAULT_ARC: Required> = { + startAngle: -90, + endAngle: 90, + cornerRadius: 0, +}; + +const DEFAULT_ANIMATION: Required = { + show: true, + duration: 1000, + easing: "cubicOut", +}; + +const DEFAULT_WIDTH = 240; +const DEFAULT_HEIGHT_RATIO = 0.68; + +const EASE_MAP: Record = { + linear: "easeLinear", + quadIn: "easeQuadIn", + quadOut: "easeQuadOut", + quadInOut: "easeQuadInOut", + cubicIn: "easeCubicIn", + cubicOut: "easeCubicOut", + cubicInOut: "easeCubicInOut", + sinIn: "easeSinIn", + sinOut: "easeSinOut", + sinInOut: "easeSinInOut", + expIn: "easeExpIn", + expOut: "easeExpOut", + expInOut: "easeExpInOut", + circleIn: "easeCircleIn", + circleOut: "easeCircleOut", + circleInOut: "easeCircleInOut", + backIn: "easeBackIn", + backOut: "easeBackOut", + backInOut: "easeBackInOut", + elasticIn: "easeElasticIn", + elasticOut: "easeElasticOut", + elasticInOut: "easeElasticInOut", + bounceIn: "easeBounceIn", + bounceOut: "easeBounceOut", + bounceInOut: "easeBounceInOut", +}; + +function resolveEase(name: GaugeEasing) { + const d3Name = EASE_MAP[name] ?? "easeCubicOut"; + return (d3 as any)[d3Name] ?? d3.easeCubicOut; +} + +function needlePixelLength( + length: GaugeNeedleConfig["length"], + radius: number +) { + if (typeof length === "number") return length; + switch (length) { + case "short": + return radius * 0.55; + case "full": + return radius * 0.95; + case "medium": + default: + return radius * 0.75; + } +} + +function needleShape( + type: NonNullable, + length: number, + width: number +) { + const w = width; + switch (type) { + case "line": + return { + tag: "line", + attrs: { + x1: 0, + y1: 0, + x2: 0, + y2: -length, + strokeWidth: w, + strokeLinecap: "butt", + }, + }; + case "rounded": + return { + tag: "line", + attrs: { + x1: 0, + y1: 0, + x2: 0, + y2: -length, + strokeWidth: w, + strokeLinecap: "round", + }, + }; + case "triangle": { + const half = w / 2; + return { + tag: "polygon", + attrs: { + points: `0,0 ${-half},${-length * 0.15} 0,${-length} ${half},${ + -length * 0.15 + }`, + }, + }; + } + case "drop": + default: { + const half = w / 2; + const d = `M ${-half} 0 + C ${-half} ${-length * 0.35}, ${-w} ${ + -length * 0.7 + }, 0 ${-length} + C ${w} ${-length * 0.7}, ${half} ${-length * 0.35}, ${half} 0 + A ${half} ${half} 0 1 1 ${-half} 0 Z`; + return { tag: "path", attrs: { d } }; + } + } +} + +function isGradientColor(c?: GaugeColor): c is string[] { + return Array.isArray(c) && c.length >= 2; +} + +function resolveFill( + defs: d3.Selection, + id: string, + color: GaugeColor | undefined, + fallback: string +): string { + if (!color) return fallback; + if (!isGradientColor(color)) return color; + + let grad = defs.select(`#${id}`); + if (grad.empty()) { + grad = defs.append("linearGradient").attr("id", id); + } + grad.attr("x1", "0%").attr("y1", "0%").attr("x2", "100%").attr("y2", "0%"); + grad.selectAll("stop").remove(); + color.forEach((c, i) => + grad + .append("stop") + .attr("offset", `${(i / (color.length - 1)) * 100}%`) + .attr("stop-color", c) + ); + return `url(#${id})`; +} + +function getArcBounds(startDeg: number, endDeg: number) { + const lo = Math.min(startDeg, endDeg); + const hi = Math.max(startDeg, endDeg); + const angles = [startDeg, endDeg]; + for (let k = Math.ceil(lo / 90) * 90; k <= hi; k += 90) angles.push(k); + + let minX = Infinity, + maxX = -Infinity, + minY = Infinity, + maxY = -Infinity; + angles.forEach((deg) => { + const a = deg * DEG2RAD; + const x = Math.sin(a); + const y = -Math.cos(a); + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + minY = Math.min(minY, y); + maxY = Math.max(maxY, y); + }); + return { minX, maxX, minY, maxY, w: maxX - minX, h: maxY - minY }; +} + +export function AnedyaGauge({ + node, + variable, + title = "Latest Value", + theme, + className, + // style, + width, + height, + minWidth = 160, + maxWidth = 480, + minHeight = 140, + maxHeight = 420, + aspectRatio, + value: valueProp, + min = 0, + max = 100, + size, + // responsive = true, + arc, + track, + color, + needle, + // valueLabel, + tick, + animation, + tooltip, // NEW + unit, + decimalPlaces, + format, + formatOptions, + formatValue, + labelText, + labelFormat, + timezone, + styles = {}, + onDataChange, + renderError, + renderEmpty, +}: AnedyaGaugeProps): React.JSX.Element { + // Runtime invariant β€” identical rule to AnedyaCard: TypeScript alone + // can't express "node+variable OR value, but not neither" across two + // independent optional props (see the comment on AnedyaWidgetBaseProps + // in common.ts for why node/variable are optional at the type level in + // the first place). Runs before any hooks below, so it's a stable + // guard clause β€” either this instance always throws on every render, + // or never does, so it can't violate the rules of hooks. + if (!node && valueProp == null) { + throw new Error( + "[AnedyaGauge] Provide either `node` (with `variable`) for live data, or a manual `value` prop for a controlled gauge β€” neither was given." + ); + } + if (node && !variable) { + throw new Error( + "[AnedyaGauge] `variable` is required whenever `node` is provided." + ); + } + + const svgRef = useRef(null); + // REQUIREMENT 2: stable "now" fallback for manual/custom `value` mode, + // captured once on mount (not recomputed every render). + const manualTimestampRef = useRef(Date.now()); + + const [fetchedValue, setFetchedValue] = useState(null); + const [timestamp, setTimestamp] = useState(null); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [isEmpty, setIsEmpty] = useState(false); + + // NEW β€” tooltip position/visibility, updated by pointer handlers attached + // to the track/bar SVG elements in the D3 draw effect below. + const [tooltipState, setTooltipState] = useState<{ + x: number; + y: number; + visible: boolean; + flipX: boolean; // ← add this + }>({ x: 0, y: 0, visible: false, flipX: false }); + + const [dynamicProps, setDynamicProps] = useState({}); + + const mountedRef = useRef(false); + const isFetchingRef = useRef(false); + + // ---- Live data fetch (mirrors AnedyaCard, plus timestamp) ---- + useEffect(() => { + if (!node) return; + mountedRef.current = true; + + const fetchLatest = async () => { + if (isFetchingRef.current) return; + isFetchingRef.current = true; + setLoading(true); + setError(null); + + try { + // `variable!` β€” TS still sees this as `string | undefined` since + // it's typed optional on the shared base props, but the runtime + // invariant check above guarantees it's set whenever we get this + // far (the effect itself also bails out early if `!node`). + const res = await node.getLatestData(variable!); + if (!mountedRef.current) return; + + if (res.isSuccess && res.isDataAvailable) { + setFetchedValue(res.data.value); + setTimestamp(res.data.timestamp); + setError(null); + setIsEmpty(false); + } else if (res.isSuccess && !res.isDataAvailable) { + // Fetch succeeded, but there's genuinely no data yet β€” distinct + // from an actual error. + setFetchedValue(null); + setTimestamp(null); + setError(null); + setIsEmpty(true); + } else { + setFetchedValue(null); + setError(res.error?.errorMessage ?? "No data available"); + setIsEmpty(false); + } + } catch (err: any) { + if (!mountedRef.current) return; + setFetchedValue(null); + setError(err?.message ?? "Failed to fetch data"); + setIsEmpty(false); + } finally { + if (mountedRef.current) { + setLoading(false); + isFetchingRef.current = false; + } + } + }; + + fetchLatest(); + return () => { + mountedRef.current = false; + }; + }, [node, variable]); + + // ---- onDataChange resolution (identical pattern to AnedyaCard) ---- + useEffect(() => { + if (!onDataChange) { + setDynamicProps({}); + return; + } + + const data = + fetchedValue != null && timestamp != null + ? { value: fetchedValue, timestamp } + : null; + const meta: GaugeDataMeta = error + ? { kind: "error", error } + : isEmpty + ? { kind: "empty" } + : { kind: "success" }; + + setDynamicProps(onDataChange(data, meta) ?? {}); + }, [fetchedValue, timestamp, error, isEmpty, onDataChange]); + + const rawValue = fetchedValue ?? valueProp ?? min; + const clampedValue = Math.min(max, Math.max(min, rawValue)); + + // REQUIREMENT 5: onValueChange effect removed (see prop removal above). + + // const { ref: wrapperRef, size: dims } = useResizeObserver( + // responsive && size == null + // ); + + const { ref: arcWrapperRef, size: dims } = useResizeObserver( + size == null + ); + + const mergedStyles = useMemo( + () => ({ ...(styles ?? {}), ...(dynamicProps.styles ?? {}) }), + [styles, dynamicProps.styles] + ); + + // ---- Merge static props with dynamic onDataChange overrides ---- + const resolvedProps = { + title, + theme, + min, + max, + width, + height, + minWidth, + maxWidth, + minHeight, + maxHeight, + aspectRatio, + size, + arc, + track, + color, + needle, + animation, + tick, + tooltip, // NEW + unit, + decimalPlaces, + className, + formatValue, + format, + formatOptions, + labelText, + labelFormat, + timezone, + renderError, + renderEmpty, + ...dynamicProps, + styles: mergedStyles, + // responsive, // not work + }; + + // ---- Resolved config ---- + const resolvedArc = { ...DEFAULT_ARC, ...resolvedProps.arc }; + + const resolvedTrack: Required = { + show: resolvedProps.track?.show ?? true, + color: resolvedProps.track?.color ?? "", + }; + + const resolvedNeedle: Required> & { + length: NonNullable; + } = { + show: resolvedProps.needle?.show ?? true, + type: resolvedProps.needle?.type ?? "rounded", + length: resolvedProps.needle?.length ?? "medium", + width: resolvedProps.needle?.width ?? 4, + color: resolvedProps.needle?.color ?? "", + needleColor: + resolvedProps.needle?.needleColor ?? + resolvedProps.needle?.color ?? + "currentColor", + capColor: + resolvedProps.needle?.capColor ?? + resolvedProps.needle?.color ?? + "currentColor", + capRadius: resolvedProps.needle?.capRadius ?? 6, + animation: resolvedProps.needle?.animation ?? true, + }; + + // const resolvedValueLabel: Required> = { + // show: resolvedProps.valueLabel?.show ?? true, + // }; + + const resolvedAnimation = { + ...DEFAULT_ANIMATION, + ...resolvedProps.animation, + }; + + // NEW β€” tooltip config, defaults to shown with the built-in + // "variable: value unit" content. + const resolvedTooltip: Required> & + Pick = { + show: resolvedProps.tooltip?.show ?? true, + content: resolvedProps.tooltip?.content, + }; + + // ---- REQUIREMENT 3/4: tick marks config ---- + // `count` = number of INTERVALS between min/max, so count=10 with the + // default min=0/max=100 draws 11 marks (0,10,20...100) β€” "10 count" per + // the ask. All sizing/color/gap knobs are user-overridable; `tick`/ + // `tickLabel` GaugeSlot entries (in `styles`) layer Tailwind classes on + // top for anything not covered by these direct props. + const resolvedTick = { + show: resolvedProps.tick?.show ?? false, + count: resolvedProps.tick?.count ?? 10, + size: resolvedProps.tick?.size ?? 6, + color: resolvedProps.tick?.color ?? "", + radiusOffset: resolvedProps.tick?.radiusOffset ?? 4, + labelGap: resolvedProps.tick?.labelGap ?? 4, + labelSize: resolvedProps.tick?.labelSize ?? 10, + labelColor: resolvedProps.tick?.labelColor ?? "", + labelFormat: resolvedProps.tick?.labelFormat, + }; + + // ---- Theme + slot classes ---- + const resolvedTheme: WidgetTheme = + resolvedProps.theme === "dark" + ? gaugeDarkTheme + : resolvedProps.theme === "light" + ? gaugeLightTheme + : (resolvedProps.theme as WidgetTheme) ?? DEFAULT_GAUGE_THEME; + + const resolveSlot = useCallback( + (slot: GaugeSlot) => + twMerge( + GAUGE_DEFAULT_CLASSES[slot], + resolvedTheme?.styles?.[slot], + resolvedProps.styles[slot] + ), + [resolvedTheme, resolvedProps.styles] + ); + + // ---- REQUIREMENT 3: tick values (min..max split into `count` even steps) ---- + const tickValues = useMemo(() => { + if (!resolvedTick.show || resolvedTick.count <= 0) return []; + const step = (resolvedProps.max - resolvedProps.min) / resolvedTick.count; + return d3 + .range(resolvedTick.count + 1) + .map((i) => resolvedProps.min + i * step); + }, [ + resolvedTick.show, + resolvedTick.count, + resolvedProps.min, + resolvedProps.max, + ]); + + // ---- REQUIREMENT 3/4: tick label formatting ---- + // Reuses the same `format` preset as the main value (if set) so tick + // labels and the big value stay consistent; falls back to a plain + // rounded number when nothing else is configured. + const formatTickLabel = useCallback( + (v: number) => { + if (resolvedTick.labelFormat) return resolvedTick.labelFormat(v); + if (resolvedProps.format) + return FORMATTERS[resolvedProps.format](v, resolvedProps.formatOptions) + .value; + return String(Math.round(v * 100) / 100); + }, + [ + resolvedTick.labelFormat, + resolvedProps.format, + resolvedProps.formatOptions, + ] + ); + + // ---- Value + unit formatting (same precedence as AnedyaCard) ---- + const { displayValue, displayUnit } = useMemo(() => { + if (resolvedProps.formatValue) { + return { + displayValue: resolvedProps.formatValue(clampedValue), + displayUnit: resolvedProps.unit, + }; + } + + if (resolvedProps.format) { + const result = FORMATTERS[resolvedProps.format]( + clampedValue, + resolvedProps.formatOptions + ); + return { displayValue: result.value, displayUnit: result.unit }; + } + + if (resolvedProps.decimalPlaces != null) { + return { + displayValue: clampedValue.toFixed(resolvedProps.decimalPlaces), + displayUnit: resolvedProps.unit, + }; + } + + return { + displayValue: String(clampedValue), + displayUnit: resolvedProps.unit, + }; + }, [ + clampedValue, + resolvedProps.formatValue, + resolvedProps.format, + resolvedProps.formatOptions, + resolvedProps.decimalPlaces, + resolvedProps.unit, + ]); + + // REQUIREMENT 2: in manual `value` mode there's no `node`, so the + // live-fetch effect never runs and `timestamp` stays null forever β€” the + // label used to just disappear in that case. Fall back to the timestamp + // captured on mount so the label still renders for custom/manual values. + const effectiveTimestamp = useMemo( + () => timestamp ?? (valueProp != null ? manualTimestampRef.current : null), + [timestamp, valueProp] + ); + + // Auto-detect the browser's timezone unless the consumer overrides it. + const resolvedTimezone = + resolvedProps.timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + + // ---- Last-updated label β€” THIS is what shows the time ---- + const displayLabel = useMemo(() => { + if (effectiveTimestamp == null) return null; + + if (resolvedProps.labelText) + return resolvedProps.labelText(effectiveTimestamp); + + const formatter = LABEL_FORMATTERS[resolvedProps.labelFormat ?? "time"]; + return formatter(effectiveTimestamp, { + locale: resolvedProps.formatOptions?.locale, + timezone: resolvedTimezone, + } as any); + }, [ + effectiveTimestamp, + resolvedProps.labelText, + resolvedProps.labelFormat, + resolvedProps.formatOptions?.locale, + resolvedTimezone, + ]); + + // NEW β€” default tooltip text: "variable: value unit". Custom `tooltip.content` + // receives the same data plus the raw clamped value. + const tooltipContent = useMemo(() => { + if (resolvedTooltip.content) { + return resolvedTooltip.content({ + variable: variable ?? "", + value: clampedValue, + displayValue, + unit: displayUnit, + }); + } + return variable + ? `${variable}: ${displayValue}${displayUnit ? ` ${displayUnit}` : ""}` + : `${displayValue}${displayUnit ? ` ${displayUnit}` : ""}`; + }, [ + resolvedTooltip.content, + variable, + clampedValue, + displayValue, + displayUnit, + ]); + + // ---- Geometry ---- + const boxWidth = + resolvedProps.size ?? resolvedProps.width ?? (dims.width || DEFAULT_WIDTH); + const boxHeight = + resolvedProps.size ?? + resolvedProps.height ?? + (dims.height || boxWidth * DEFAULT_HEIGHT_RATIO); + + const bounds = useMemo( + () => getArcBounds(resolvedArc.startAngle, resolvedArc.endAngle), + [resolvedArc.startAngle, resolvedArc.endAngle] + ); + + const pad = 8; + // const textReserve = resolvedValueLabel.show ? 0.34 : 0.16; + const textReserve = 0; + const availW = boxWidth - pad * 2; + const availH = boxHeight * (1 - textReserve) - pad * 2; + + // REQUIREMENT 3: reserve room for the tick ring (line + gaps + label) + // so ticks never get clipped by the SVG viewBox. Rather than growing the + // outer container, we shrink the arc radius by this padding β€” the whole + // gauge (arc + ticks) then always fits inside whatever box the + // responsive container currently has. + const tickPadding = resolvedTick.show + ? resolvedTick.radiusOffset + + resolvedTick.size + + resolvedTick.labelGap + + resolvedTick.labelSize * 1.5 + : 0; + + const maxFitRadius = Math.max( + 24, + Math.min( + (availW - tickPadding * 2) / (bounds.w || 1), + (availH - tickPadding * 2) / (bounds.h || 1) + ) + ); + + const outerRadius = resolvedArc.radius + ? Math.min(resolvedArc.radius, maxFitRadius) + : maxFitRadius; + + const thickness = resolvedArc.thickness ?? Math.max(6, outerRadius * 0.18); + + const cx = + pad - bounds.minX * outerRadius + (availW - bounds.w * outerRadius) / 2; + const cy = pad - bounds.minY * outerRadius; + + const angleScale = useMemo( + () => + d3 + .scaleLinear() + .domain([resolvedProps.min, resolvedProps.max]) + .range([ + resolvedArc.startAngle * DEG2RAD, + resolvedArc.endAngle * DEG2RAD, + ]) + .clamp(true), + [ + resolvedProps.min, + resolvedProps.max, + resolvedArc.startAngle, + resolvedArc.endAngle, + ] + ); + + // ---- D3 draw ---- + useEffect(() => { + if (!svgRef.current || boxWidth === 0 || boxHeight === 0) return; + + const svg = d3.select(svgRef.current); + const defs = svg.select("defs"); + const root = svg.select("g.anedya-gauge-root"); + root.attr("transform", `translate(${cx},${cy})`); + + const ease = resolveEase(resolvedAnimation.easing); + const safeCornerRadius = Math.min(resolvedArc.cornerRadius, thickness / 2); + + const arcGen = d3 + .arc<{ startAngle: number; endAngle: number; r: number }>() + .innerRadius((d) => d.r - thickness) + .outerRadius((d) => d.r) + .cornerRadius(safeCornerRadius) + .startAngle((d) => d.startAngle) + .endAngle((d) => d.endAngle); + + const startA = resolvedArc.startAngle * DEG2RAD; + const endA = resolvedArc.endAngle * DEG2RAD; + + // NEW β€” shared pointer handlers for the tooltip. Position is computed + // relative to the arc wrapper div (the tooltip's positioning parent), + // not the SVG, since the SVG's internal viewBox coordinate space can + // differ from its rendered CSS size. + const handleTooltipMove = (event: MouseEvent) => { + const wrapperEl = arcWrapperRef.current as HTMLDivElement | null; + if (!wrapperEl) return; + const rect = wrapperEl.getBoundingClientRect(); + const relX = event.clientX - rect.left; + const flipX = relX > rect.width * 0.5; + setTooltipState({ + visible: true, + x: relX, + y: event.clientY - rect.top, + flipX, + }); + }; + const handleTooltipLeave = () => { + setTooltipState((s) => (s.visible ? { ...s, visible: false } : s)); + }; + + const trackSel = root.select( + "path.anedya-gauge-track-path" + ); + if (resolvedTrack.show) { + trackSel + .attr( + "d", + arcGen({ startAngle: startA, endAngle: endA, r: outerRadius })! + ) + .attr("fill", resolvedTrack.color || "currentColor") + .attr("opacity", 1); + } else { + trackSel.attr("opacity", 0); + } + + // NEW β€” attach/detach tooltip listeners on the track, gated by + // resolvedTooltip.show (added to this effect's dependency array below). + if (resolvedTooltip.show) { + trackSel + .style("cursor", "pointer") + .on("mousemove", handleTooltipMove) + .on("mouseleave", handleTooltipLeave); + } else { + trackSel + .style("cursor", null) + .on("mousemove", null) + .on("mouseleave", null); + } + + // ---- REQUIREMENT 3/4: tick marks + labels ---- + // Ticks don't animate (they're static reference marks), so it's a + // simple remove-and-redraw each time rather than the persistent-node + // + transition pattern used for the bar/needle. + const tickGroup = root.select("g.anedya-gauge-ticks"); + tickGroup.selectAll("*").remove(); + + if (resolvedTick.show) { + const lineStartR = outerRadius + resolvedTick.radiusOffset; + const lineEndR = lineStartR + resolvedTick.size; + const labelR = lineEndR + resolvedTick.labelGap; + + tickValues.forEach((v) => { + const angleDeg = angleScale(v) / DEG2RAD; + + // Tick line: drawn pointing "up" then rotated into place β€” the + // rotate-then-translate idea is the one piece taken from the + // reference D3 gauge's tick-label positioning. + tickGroup + .append("line") + .attr("class", twMerge("anedya-gauge-tick", resolveSlot("tick"))) + .attr("x1", 0) + .attr("y1", -lineStartR) + .attr("x2", 0) + .attr("y2", -lineEndR) + .attr("stroke", resolvedTick.color || "currentColor") + .attr("stroke-width", 1.5) + .attr("transform", `rotate(${angleDeg})`); + + // Tick label: rotate to the tick's angle, translate out to its + // radius, then rotate back β€” keeps every label upright/horizontal + // no matter where it sits around the arc. font-size is set via + // `.style()` (inline style) so `tick.labelSize` always wins over + // any Tailwind class on the `tickLabel` slot. + tickGroup + .append("text") + .attr( + "class", + twMerge("anedya-gauge-tick-label", resolveSlot("tickLabel")) + ) + .attr("text-anchor", "middle") + .attr("dominant-baseline", "middle") + .style("font-size", `${resolvedTick.labelSize}px`) + .attr("fill", resolvedTick.labelColor || "currentColor") + .attr( + "transform", + `rotate(${angleDeg}) translate(0, ${-labelR}) rotate(${-angleDeg})` + ) + .text(formatTickLabel(v)); + }); + } + + const barGroup = root.select("g.anedya-gauge-bar-group"); + + const barValue = loading || error ? resolvedProps.min : clampedValue; + const valueAngle = angleScale(barValue); + const barFill = resolveFill( + defs, + "anedya-gauge-bar-fill", + resolvedProps.color, + "currentColor" + ); + + let path = barGroup.select("path.anedya-gauge-bar-path"); + if (path.empty()) { + path = barGroup + .append("path") + .attr("class", "anedya-gauge-bar-path") + .attr("data-end-angle", String(startA)); + } + + path + .attr("class", twMerge("anedya-gauge-bar-path", resolveSlot("bar"))) + .attr("fill", barFill) + .attr("stroke", "none") + .attr("opacity", loading ? 0.4 : 1); + + // NEW β€” same tooltip listeners on the filled bar, so hovering the + // active portion of the arc (not just the track) also triggers it. + if (resolvedTooltip.show) { + path + .style("cursor", "pointer") + .on("mousemove", handleTooltipMove) + .on("mouseleave", handleTooltipLeave); + } else { + path.style("cursor", null).on("mousemove", null).on("mouseleave", null); + } + + const currentEndAngle = path.attr("data-end-angle") + ? +path.attr("data-end-angle")! + : startA; + + if (resolvedAnimation.show) { + path + .datum({ + startAngle: startA, + endAngle: currentEndAngle, + r: outerRadius, + }) + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("d", function (d: any) { + const interp = d3.interpolate(d.endAngle, valueAngle); + return (t) => { + d.endAngle = interp(t); + path.attr("data-end-angle", String(d.endAngle)); + return arcGen({ + startAngle: startA, + endAngle: d.endAngle, + r: outerRadius, + })!; + }; + }); + } else { + // NEW: animation disabled β€” snap straight to the target angle, no tween + path + .datum({ startAngle: startA, endAngle: valueAngle, r: outerRadius }) + .attr("data-end-angle", String(valueAngle)) + .attr( + "d", + arcGen({ startAngle: startA, endAngle: valueAngle, r: outerRadius })! + ); + } + + const needleGroup = root.select("g.anedya-gauge-needle"); + if (resolvedNeedle.show) { + const len = needlePixelLength(resolvedNeedle.length, outerRadius); + const shape = needleShape(resolvedNeedle.type, len, resolvedNeedle.width); + + needleGroup.selectAll("*:not(circle.anedya-gauge-needle-cap)").remove(); + const needleEl = needleGroup.insert( + shape.tag as any, + "circle.anedya-gauge-needle-cap" + ); + needleEl.attr("class", resolveSlot("needle")); + + needleEl + .attr("class", resolveSlot("needle")) + .attr("fill", resolvedNeedle.needleColor) + .attr("stroke", resolvedNeedle.needleColor) + .attr("opacity", loading ? 0.4 : 1); + + Object.entries(shape.attrs).forEach(([k, v]) => + needleEl.attr( + k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()), + v as any + ) + ); + + let cap = needleGroup.select( + "circle.anedya-gauge-needle-cap" + ); + if (cap.empty()) { + cap = needleGroup + .append("circle") + .attr( + "class", + twMerge("anedya-gauge-needle-cap", resolveSlot("needleCap")) + ); + } + cap + .attr("r", resolvedNeedle.capRadius) + .attr("fill", resolvedNeedle.capColor) // ← use capColor + .attr("opacity", loading ? 0.4 : 1); + + const targetDeg = valueAngle / DEG2RAD; + // NEW: needle now only animates if BOTH the per-needle flag AND the + // global resolvedAnimation.show are true + if (resolvedNeedle.animation && resolvedAnimation.show) { + needleGroup + .transition() + .duration(resolvedAnimation.duration) + .ease(ease) + .attrTween("transform", function () { + const current = needleGroup.attr("data-angle") + ? +needleGroup.attr("data-angle")! + : startA / DEG2RAD; + const interp = d3.interpolate(current, targetDeg); + return (t) => { + const a = interp(t); + needleGroup.attr("data-angle", String(a)); + return `rotate(${a})`; + }; + }); + } else { + needleGroup + .attr("transform", `rotate(${targetDeg})`) + .attr("data-angle", String(targetDeg)); + } + needleGroup.attr("opacity", 1); + } else { + needleGroup.attr("opacity", 0); + } + + // NEW β€” hide the tooltip immediately if the pointer leaves the SVG + // entirely (not just the track/bar shapes specifically). + if (resolvedTooltip.show) { + svg.on("mouseleave", handleTooltipLeave); + } else { + svg.on("mouseleave", null); + setTooltipState((s) => (s.visible ? { ...s, visible: false } : s)); + } + }, [ + boxWidth, + boxHeight, + cx, + cy, + outerRadius, + thickness, + clampedValue, + loading, + error, + resolvedProps.min, + resolvedProps.max, + resolvedProps.color, + resolvedArc.cornerRadius, + resolvedTrack.show, + resolvedTrack.color, + resolvedNeedle.show, + resolvedNeedle.type, + resolvedNeedle.length, + resolvedNeedle.width, + resolvedNeedle.color, + resolvedNeedle.capRadius, + resolvedNeedle.animation, + resolvedAnimation.duration, + resolvedAnimation.easing, + resolvedAnimation.show, + resolvedTick.show, + resolvedTick.count, + resolvedTick.size, + resolvedTick.color, + resolvedTick.radiusOffset, + resolvedTick.labelGap, + resolvedTick.labelSize, + resolvedTick.labelColor, + resolvedTooltip.show, // NEW + tickValues, + formatTickLabel, + resolveSlot, + arcWrapperRef, // NEW β€” used inside handleTooltipMove + ]); + + // const handleClick = useCallback( + // () => onClick?.(clampedValue), + // [onClick, clampedValue] + // ); + + // REQUIREMENT 1: value/unit/label extracted so the exact same markup can + // be placed either below the arc (needle mode) or centered over it + // (no-needle / donut mode) without duplicating JSX. + const valueBlock = ( + <> + + {displayValue} + {displayUnit && ( + {displayUnit} + )} + + {displayLabel && ( + {displayLabel} + )} + + ); + + return ( +
+ {/*
+ {resolvedProps.title && ( + {resolvedProps.title} + )} */} +
+ {resolvedProps.title && ( + {resolvedProps.title} + )} + + {/* REQUIREMENT 1: wrapped in a relative container so the centered + value/label overlay (no-needle mode) can be positioned directly + on top of the arc. min-h-0 keeps this shrinkable inside the + flex-column layout instead of overflowing it. */} +
+ + + + + {/* REQUIREMENT 3/4: tick marks + labels, populated in the D3 draw effect */} + + + + + + + + + {/* REQUIREMENT 1: no needle β†’ treat it like a donut and center the + value/label directly over the arc's visual center (cx, cy). + Position is expressed as a % of the viewBox so it stays correct + at any container size. */} + {!resolvedNeedle.show && !loading && !error && !isEmpty && ( +
+ {valueBlock} +
+ )} + + {/* NEW β€” tooltip. Positioned relative to this wrapper div (which is + already `relative`), follows the pointer via tooltipState.x/y + set by the D3 mousemove handlers above, and hides on mouseleave. */} + {resolvedTooltip.show && + tooltipState.visible && + !loading && + !error && + !isEmpty && ( +
+ {tooltipContent} +
+ )} +
+ + {loading ? ( +
+
+
+
+ ) : error ? ( + resolvedProps.renderError ? ( + resolvedProps.renderError(error) + ) : ( + {error} + ) + ) : isEmpty ? ( + resolvedProps.renderEmpty ? ( + resolvedProps.renderEmpty() + ) : ( + N/A + ) + ) : ( + // REQUIREMENT 1: needle-mode keeps the original below-the-arc + // layout. No-needle mode already rendered `valueBlock` centered above. + resolvedNeedle.show && valueBlock + )} +
+
+ ); +} From 7ae77f8a4e5b1ba92ca362bd2965bda48a669ec8 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 28 Jul 2026 16:21:43 +0530 Subject: [PATCH 60/66] commit --- .../application-example/package-lock.json | 42 ++++++------------- examples/application-example/src/App.jsx | 3 ++ src/styles/base.css | 2 +- src/themes/gaugeTheme.ts | 2 +- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/examples/application-example/package-lock.json b/examples/application-example/package-lock.json index cddce2ca..9898be34 100644 --- a/examples/application-example/package-lock.json +++ b/examples/application-example/package-lock.json @@ -89,6 +89,7 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -321,17 +322,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -407,6 +397,7 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -450,6 +441,7 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -996,7 +988,6 @@ "integrity": "sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/Boshen" } @@ -1024,7 +1015,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1042,7 +1032,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1060,7 +1049,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1078,7 +1066,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1096,7 +1083,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1114,7 +1100,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1132,7 +1117,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1150,7 +1134,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1168,7 +1151,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1186,7 +1168,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1204,7 +1185,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1222,7 +1202,6 @@ "os": [ "openharmony" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1237,7 +1216,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/core": "1.11.2", "@emnapi/runtime": "1.11.2", @@ -1254,7 +1232,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" @@ -1267,7 +1244,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -1285,7 +1261,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1303,7 +1278,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": "^20.19.0 || >=22.12.0" } @@ -1314,6 +1288,7 @@ "integrity": "sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "picomatch": "^4.0.4" }, @@ -1921,6 +1896,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -1976,6 +1952,7 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2058,6 +2035,7 @@ "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -2113,6 +2091,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.44", "caniuse-lite": "^1.0.30001806", @@ -2374,6 +2353,7 @@ "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3562,6 +3542,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -3571,6 +3552,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -3873,6 +3855,7 @@ "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.5", @@ -4321,6 +4304,7 @@ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/examples/application-example/src/App.jsx b/examples/application-example/src/App.jsx index a706b854..370f65ae 100644 --- a/examples/application-example/src/App.jsx +++ b/examples/application-example/src/App.jsx @@ -242,6 +242,9 @@ export default function App() { needle={{ show: true, length: "medium", width: 6 }} tick={{ show: true, count: 10, size: 6, labelSize: 11 }} color="#10B981" + styles={{ + tooltip:"bg-black text-white" + }} /> {/* ---------------------------------------------------------------- diff --git a/src/styles/base.css b/src/styles/base.css index e3ae50f5..da972fda 100644 --- a/src/styles/base.css +++ b/src/styles/base.css @@ -36,7 +36,7 @@ .anedya-gauge { --anedya-gauge-padding: clamp(1rem, 0.5rem + 2.5cqw + 2.5cqh, 4.5rem); --anedya-gauge-title-size: clamp(0.875rem, 0.6rem + 1.5cqw + 1.5cqh, 3rem); - --anedya-gauge-value-size: clamp(2.25rem, 1rem + 8cqw + 8cqh, 9.5rem); + --anedya-gauge-value-size: clamp(1.6rem, 0.8rem + 4cqw + 4cqh, 4.5rem); --anedya-gauge-unit-size: clamp(1rem, 0.7rem + 1.5cqw + 1.5cqh, 3.25rem); --anedya-gauge-label-size: clamp(0.75rem, 0.5rem + 1.2cqw + 1.2cqh, 2.25rem); --anedya-gauge-tick-size: clamp(0.625rem, 0.4rem + 0.6cqw + 0.6cqh, 0.875rem); diff --git a/src/themes/gaugeTheme.ts b/src/themes/gaugeTheme.ts index a0b83bed..99aef227 100644 --- a/src/themes/gaugeTheme.ts +++ b/src/themes/gaugeTheme.ts @@ -20,7 +20,7 @@ export const GAUGE_DEFAULT_CLASSES: Record = { // needs non-size utilities. tickLabel: "font-medium select-none", error: "text-sm font-medium", - empty: "text-[length:var(--anedya-card-value-size)] font-bold", + empty: "text-[length:var(--anedya-gauge-value-size)] font-bold", tooltip: "pointer-events-none z-10 rounded-md px-2 text-[length:var(--anedya-gauge-tooltip-size)] shadow-lg whitespace-nowrap font-medium", }; From 7180d6d466500574925d50c35c14baedbaee72b5 Mon Sep 17 00:00:00 2001 From: yashcoddee Date: Tue, 28 Jul 2026 16:22:49 +0530 Subject: [PATCH 61/66] remove unwanted files --- test/my-app/src/App.jsx | 526 ---------------------------------------- 1 file changed, 526 deletions(-) delete mode 100644 test/my-app/src/App.jsx diff --git a/test/my-app/src/App.jsx b/test/my-app/src/App.jsx deleted file mode 100644 index 2f05fb7c..00000000 --- a/test/my-app/src/App.jsx +++ /dev/null @@ -1,526 +0,0 @@ -import React from "react"; -import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { CardWidget } from "../../../src"; -import { GaugeWidget } from "../../../src/components/GaugeChart/GaugeChartWidget"; -import "public-widget-sdk/styles.css"; -import { relativeTime } from "public-widget-sdk/formatters"; -import "./index.css"; -// This demo has its own Tailwind build (see vite.config.js + src/index.css), -// specifically to test consumer-side class overrides via `className`/`styles`. -// A real consumer app needs the same setup β€” the widget package's own -// precompiled stylesheet only covers its built-in default classes, not -// arbitrary classes a consumer passes in. - -const tokenId = import.meta.env.VITE_CARD_WIDGET_TOKEN_ID; -const token = import.meta.env.VITE_CARD_WIDGET_TOKEN; -const nodeId = import.meta.env.VITE_CARD_WIDGET_NODE_ID; - -const anedya = new Anedya(); -const config = anedya.newConfig(tokenId, token); -const client = anedya.newClient(config); -const node = anedya.newNode(client, nodeId); - -/** - * A reusable theme, shareable across every CardWidget instance in your - * app. Only specify the slots you actually want to change from the - * built-in default β€” anything omitted falls back to lightTheme/darkTheme. - */ -const emeraldTheme = { - styles: { - container: "bg-emerald-50 border-emerald-200", - title: "text-emerald-700", - value: "text-emerald-900", - label: "text-emerald-500", - }, -}; - -export const gaugeCustomLightTheme = { - styles: { - // Tailwind classes for HTML container and text wrappers - container: "bg-emerald-50 border-emerald-200", - title: "text-emerald-800", - value: "text-emerald-950", - label: "text-emerald-600", - - // Hex colors for D3 SVG elements - track: "#E2E8F0", // Soft gray background arc (slate-200) - bar: "#10B981", // Primary value fill (emerald-500) - needle: "#047857", // Darker accent needle for high visibility (emerald-700) - needleCap: "#065F46", // Needle center cap (emerald-800) - }, -}; - -export const gaugeCustomDarkTheme = { - styles: { - // Tailwind classes for HTML container and text wrappers - container: "bg-yellow-500 border-emerald-800/50 backdrop-blur-sm", - title: "text-red-500", - value: "text-yellow-500", - label: "text-red-500", - - // Hex colors for D3 SVG elements - track: "text-red-500", // Dark muted background arc (slate-800) - bar: "text-yellow-500", // High-contrast bright fill (emerald-400) - needle: "text-red-500", // Bright needle for dark mode contrast (emerald-300) - needleCap: "text-yellow-500", // Bright needle center cap (emerald-200) - }, -}; - -const commonProps = { node, variable: "humidity" }; - -export default function App() { - return ( -
- {/* ============================================================ - * 1. Default appearance β€” no theme, no styles, no - * formatting props. Every fallback in the widget in one place. - * ============================================================ */} - { - if (meta.kind === "error") { - return { - renderError: () => ( - - Sensor unreachable - - ), - }; - } - if (meta.kind === "empty") { - return { - renderEmpty: () => ( - β€” no reading yet β€” - ), - }; - } - }} - /> - - {/* ============================================================ - * 2. theme β€” a reusable, shareable WidgetTheme object. Same - * effect across every widget instance that uses it. - * ============================================================ */} - - {/* Built-in preset names also work directly: */} - - {/* ============================================================ - * 3. styles vs className β€” THE distinction to understand: - * - * - `styles` (plural, an OBJECT): per-SLOT overrides. - * Keys are "container" | "title" | "value" | "unit" | "label" - * β€” lets you reach INSIDE the widget and style individual - * pieces independently. - * - * - `className` (singular, a STRING): the ordinary React - * convention β€” one class applied ONLY to the widget's - * outermost container element, same as you'd pass to any - * other component. It's merged (via twMerge) with whatever - * styles.container already resolved to, not a - * replacement for it. - * - * This example uses BOTH at once so the difference is visible: - * className adds a shadow to the outer box, styles.value/ - * styles.title style two INNER pieces independently. - * ============================================================ */} - - {/* ============================================================ - * 4. Plain CSS classes β€” styles works with ANY class source, - * not just Tailwind. These reference plain hand-written CSS - * classes (e.g. defined in a .css file this app already imports). - * ============================================================ */} - {/* */} - {/* ============================================================ - * 5. Native Tailwind responsive prefixes β€” `sm:`/`md:`/`lg:` - * work exactly as they do anywhere else in your app, because - * styles just forwards whatever string you write straight - * to `className`. This widget does NOT have its own custom - * breakpoint system β€” these prefixes are compiled by YOUR - * project's Tailwind config and respond to the BROWSER VIEWPORT, - * same as native Tailwind everywhere else. If your own - * tailwind.config.js customizes `theme.screens`, these prefixes - * automatically follow that customization too β€” nothing to - * configure on the widget's side. - * ============================================================ */} - {/* */} - {/* ============================================================ - * 6. formatValue / labelText β€” simple formatting hooks, distinct - * from styling. formatValue controls the displayed number's - * text; labelText controls the caption under it. - * ============================================================ */} - {/* `${v.toFixed(2)} % RH`} - labelText={(ts) => `As of ${new Date(ts).toLocaleDateString()}`} - - /> */} - {/* ============================================================ - * 7. onStyleChange β€” conditional class overrides driven by the - * RAW fetched data ({ value, timestamp }), always applied on top - * of everything else (theme, styles, className). - * ============================================================ */} - {/* { - if (!data) return; - - if (data.value > 80) { - return { - title: "High Humidity", - theme: "dark", - styles: { - value: "text-red-500" - } - }; - } - - return { - title: "Humidity", - theme: "light" - }; - }} - - /> */} - {/* ============================================================ - * 8. Sizing β€” width/height/minWidth/maxWidth are plain props, - * applied as inline styles on the container, independent of the - * whole styles/theme system. - * ============================================================ */} - {/* */} - - { - if (!data) return {}; - const { value } = data; - if (value > 60) return { title: "πŸ”΄ Critical", color: "#dc2626" }; - if (value > 50) return { title: "🟑 Warning", color: "#f59e0b" }; - return { title: "🟒 Normal", color: "#10b981" }; - }} - // styles={{ - // container:"", - // // "bg-slate-50 dark:bg-slate-800 rounded-2xl shadow-lg border", - // title: "text-base font-bold tracking-wide", - // value: "text-[100px]", - // unit: "text-[200px] opacity-75", - // label: "text-xs italic text-gray-500", - // }} - /> - - - - {/* val + " km/h", - }} - animation={{ - show: true, - duration: 3000, - easing: "bounceIn", - }} - style={{ backgroundColor: "yellow" }} - /> */} - -

Testing All Gauge Widget Props

- - - - `Hello ${v} km/h`} - // labelFormat="relative" - // labelFormat="date" - labelText={(ts) => `Refreshed at ${new Date(ts).toLocaleTimeString()}`} // format="bytes" - // formatOptions={{"binary":true,"precision":2}} - - // value={1234567.891} - // format="number" - // formatOptions={{"locale":"de-DE","precision":2}} - /> - - - - { - if (!data) { - return { - title: "No Data", - color: "#6b7280", - }; - } - - const isCritical = data.value > 70; - const isWarning = data.value > 40 && data.value <= 60; - - return { - // top-level scalar/config overrides - title: isCritical ? "Critical" : isWarning ? "Warning" : "Normal", - color: isCritical ? "#ef4444" : isWarning ? "#f59e0b" : "#10b981", - unit: "Β°C", - formatValue: (v) => `${v.toFixed(1)}`, - labelText: (ts) => `Sampled ${new Date(ts).toLocaleTimeString()}`, - needle: { needleColor: isCritical ? "#ef4444" : "#10b981" }, - track: { color: isCritical ? "#450a0a" : "#052e2b" }, - animation: { duration: isCritical ? 400 : 1000 }, - - // per-slot class overrides β€” merges with (doesn't replace) the static `styles` prop - styles: { - value: isCritical - ? "text-red-500 animate-pulse" - : "text-yellow-500", - title: isCritical ? "text-red-400" : "text-slate-400", - }, - }; - }} - /> - - ( -
- ⚠ Sensor unreachable - {error} -
- )} - renderEmpty={() => ( - β€” no reading yet β€” - )} - /> - - - - - - - `πŸ“Š ${variable} β†’ ${displayValue}${unit ?? ""}`, - }} - styles={{ - tooltip:"bg-indigo-600 text-white text-sm px-3 py-1.5" - }} - /> -
- ); -} - -{ - /* -//create react app -//link public-widget-sdk -//npm run dev -//send this file tp yash to copy paste */ -} - From 6035924287999dedd60765d3bd314aed14ff3f77 Mon Sep 17 00:00:00 2001 From: surajmaurya-git Date: Tue, 28 Jul 2026 16:40:12 +0530 Subject: [PATCH 62/66] Update package name and version, adjust imports, and remove example environment file --- CONTRIBUTING.md | 8 +- README.md | 10 +- examples/application-example/.env.example | 3 - examples/application-example/index.html | 2 +- .../application-example/package-lock.json | 3 +- examples/application-example/src/App.jsx | 143 ++---------------- package-lock.json | 38 +++-- package.json | 4 +- 8 files changed, 55 insertions(+), 156 deletions(-) delete mode 100644 examples/application-example/.env.example diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 54853301..3dbfa3a3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,7 +15,7 @@ This document covers internal build setup for people working on this SDK itself Since this SDK is installed as a real package (not copied into the consumer's own repo, the way shadcn/ui works), the consumer's own Tailwind build **never scans this package's source files** by default β€” so every class string in files like `themes/defaultTheme.ts` / `CARD_DEFAULT_CLASSES` compiles to nothing in their app, and every widget would render with zero layout or color. -The fix: this SDK ships its **own pre-compiled stylesheet** as part of its build, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. This is why every consumer-facing widget needs `import "anedya-widgets-react/styles.css"` β€” see the README's [Stylesheet import](./README.md#stylesheet-import) section for the consumer-facing side of this. +The fix: this SDK ships its **own pre-compiled stylesheet** as part of its build, so consumers import real, already-compiled CSS rather than relying on their own Tailwind config to happen to pick up ours. This is why every consumer-facing widget needs `import "@anedyasystems/anedya-widgets-react/styles.css"` β€” see the README's [Stylesheet import](./README.md#stylesheet-import) section for the consumer-facing side of this. --- @@ -99,7 +99,7 @@ npm link **2. In the demo app**, link to it: ```bash -npm link anedya-widgets-react +npm link @anedyasystems/anedya-widgets-react ``` This creates a symlink from the demo's `node_modules/anedya-widgets-react` to your local package root β€” the demo now resolves that import to your local working copy instead of anything published to npm. @@ -125,8 +125,8 @@ before it shows up in the demo, even in this mode. **Option B β€” import as the published package (accurate consumer simulation)** ```jsx -import { AnedyaCard } from "anedya-widgets-react"; -import "anedya-widgets-react/styles.css"; +import { AnedyaCard } from "@anedyasystems/anedya-widgets-react"; +import "@anedyasystems/anedya-widgets-react/styles.css"; ``` Use this to verify the package behaves correctly as an actual installed dependency β€” e.g. confirming `exports` map entries resolve correctly, the stylesheet subpath import works, and nothing that only exists in the local `src/` folder (but wasn't actually exported) is accidentally being relied on. diff --git a/README.md b/README.md index 2ab07fc6..9e8d507e 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Widgets in this SDK don't create their own Anedya client or node β€” they only r **1. Install both packages:** ```bash -npm install @anedyasystems/anedya-frontend-sdk anedya-widgets-react +npm install @anedyasystems/anedya-frontend-sdk @anedyasystems/anedya-widgets-react ``` **2. Import the stylesheet once**, anywhere in your app's entry point: @@ -73,7 +73,7 @@ import "anedya-widgets-react/styles.css"; ```jsx import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { AnedyaCard } from "anedya-widgets-react"; +import { AnedyaCard } from "@anedyasystems/anedya-widgets-react"; import "anedya-widgets-react/styles.css"; const anedya = new Anedya(); @@ -844,7 +844,7 @@ Available presets: // "Updated 2:32 PM" // Combining relative time with custom text -import { relativeTime } from "anedya-widgets-react/formatters"; +import { relativeTime } from "@anedyasystems/anedya-widgets-react/formatters"; `Last synced ${relativeTime(ts)}`} />; // "Last synced 5 minutes ago" @@ -972,7 +972,7 @@ This is backwards compatible β€” existing `onDataChange={(data) => {...}}` callb The formatting helpers used internally are also available as a standalone import, for composing into your own `labelText`/`formatValue` functions β€” usable with either widget: ```tsx -import { relativeTime } from "anedya-widgets-react/formatters"; +import { relativeTime } from "@anedyasystems/anedya-widgets-react/formatters"; ``` | Export | Signature | Description | @@ -1129,7 +1129,7 @@ This SDK ships pre-compiled CSS alongside its JavaScript β€” you don't need Tail **Import the stylesheet once**, anywhere in your app's entry point (e.g. `main.tsx`, `App.tsx`, or your global styles file): ```jsx -import "anedya-widgets-react/styles.css"; +import "@anedyasystems/anedya-widgets-react/styles.css"; ``` That's the entire integration on your end. No `content` glob changes to your `tailwind.config`, no build coordination, nothing else required β€” every widget in this SDK will render fully styled as soon as this import is present. diff --git a/examples/application-example/.env.example b/examples/application-example/.env.example deleted file mode 100644 index ec1a2dc6..00000000 --- a/examples/application-example/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -VITE_CARD_WIDGET_TOKEN_ID="your_token_id_here" -VITE_CARD_WIDGET_TOKEN="your_token_secret_here" -VITE_CARD_WIDGET_NODE_ID="your_node_id_here" \ No newline at end of file diff --git a/examples/application-example/index.html b/examples/application-example/index.html index 53beb493..b327993c 100644 --- a/examples/application-example/index.html +++ b/examples/application-example/index.html @@ -4,7 +4,7 @@ - my-app + anedya-widgets-react
diff --git a/examples/application-example/package-lock.json b/examples/application-example/package-lock.json index 9898be34..5019875a 100644 --- a/examples/application-example/package-lock.json +++ b/examples/application-example/package-lock.json @@ -33,7 +33,8 @@ } }, "../..": { - "version": "5.5.0", + "name": "@anedyasystems/anedya-widgets-react", + "version": "0.0.1", "license": "ISC", "dependencies": { "@anedyasystems/anedya-frontend-sdk": "^0.1.1", diff --git a/examples/application-example/src/App.jsx b/examples/application-example/src/App.jsx index 370f65ae..6680720f 100644 --- a/examples/application-example/src/App.jsx +++ b/examples/application-example/src/App.jsx @@ -1,8 +1,8 @@ import React from "react"; import { Anedya } from "@anedyasystems/anedya-frontend-sdk"; -import { AnedyaCard } from "anedya-widgets-react"; -import { AnedyaGauge } from "anedya-widgets-react"; -import "anedya-widgets-react/styles.css"; +import { AnedyaCard } from "@anedyasystems/anedya-widgets-react"; +import { AnedyaGauge } from "@anedyasystems/anedya-widgets-react"; +import "@anedyasystems/anedya-widgets-react/styles.css"; import "./index.css"; // This demo has its own Tailwind build (see vite.config.js + src/index.css), @@ -75,6 +75,16 @@ export default function App() { alignItems: "flex-start", // prevents one tall card from stretching its row-siblings β€” see README/Sizing }} > + +
+

Anedya React Widgets Example

+

+ A live demo of the Anedya React widget SDK, showing the built-in + default behavior and some common customization patterns. +

+
+ + {/* ================================================================ * SECTION 1 β€” AnedyaCard * ================================================================ */} @@ -129,88 +139,6 @@ export default function App() { }} /> - {/* ---------------------------------------------------------------- - * 1.4 formatValue / format / labelText / labelFormat β€” see README - * "Formatting vs rendering" and "The last-updated label" sections - * for the full precedence rules. formatValue/labelText are full - * escape hatches; format/labelFormat are zero-code presets. - * ---------------------------------------------------------------- */} - `${v.toFixed(2)} % RH`} - labelFormat="relative" - /> - - {/* ---------------------------------------------------------------- - * 1.5 Error & empty states β€” onDataChange's second argument - * (`meta`) tells you which state just occurred, so you can swap in - * fully custom JSX via renderError/renderEmpty. See README "Error - * & empty states" for the full behavior and styles.error/empty. - * ---------------------------------------------------------------- */} - { - if (meta.kind === "error") { - return { - renderError: () => ( - Sensor unreachable - ), - }; - } - if (meta.kind === "empty") { - return { - renderEmpty: () => ( - β€” no reading yet β€” - ), - }; - } - }} - /> - - {/* ---------------------------------------------------------------- - * 1.6 onDataChange β€” conditional overrides driven by the RAW - * fetched data ({ value, timestamp }), applied on top of - * everything else (theme, styles, className). - * ---------------------------------------------------------------- */} - { - if (!data) return; - if (data.value > 80) { - return { title: "High Humidity", theme: "dark", styles: { value: "text-red-500" } }; - } - return { title: "Humidity", theme: "light" }; - }} - /> - - {/* ---------------------------------------------------------------- - * 1.7 Sizing β€” width/height/minWidth/maxWidth are plain props, - * applied as inline styles on the container. See README "Sizing" - * β€” `height` has two distinct modes (auto-grow vs. fixed+clip). - * ---------------------------------------------------------------- */} - - - {/* ---------------------------------------------------------------- - * 1.8 timezone β€” pins the last-updated label to a specific IANA - * timezone instead of the visitor's auto-detected one. - * ---------------------------------------------------------------- */} - - {/* ================================================================ * SECTION 2 β€” AnedyaGauge * ================================================================ */} @@ -247,6 +175,7 @@ export default function App() { }} /> + {/* ---------------------------------------------------------------- * 2.4 onDataChange β€” same pattern as AnedyaCard: conditional * overrides (title, color, needle color, track color, animation @@ -286,50 +215,6 @@ export default function App() { formatValue={(v) => `${v} km/h`} labelText={(ts) => `Refreshed at ${new Date(ts).toLocaleTimeString()}`} /> - - {/* ---------------------------------------------------------------- - * 2.6 Per-slot styles β€” including the SVG-backed slots - * (track/bar/needle/needleCap/tick/tickLabel), which accept hex - * colors or `text-*` Tailwind classes (read via currentColor). - * ---------------------------------------------------------------- */} - - - {/* ---------------------------------------------------------------- - * 2.7 Error & empty states β€” identical mechanism to AnedyaCard. - * ---------------------------------------------------------------- */} - ( -
- ⚠ Sensor unreachable - {error} -
- )} - renderEmpty={() => β€” no reading yet β€”} - /> - - {/* ---------------------------------------------------------------- - * 2.8 timezone β€” same as AnedyaCard's. - * ---------------------------------------------------------------- */} -
); } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 64abeff3..68f19fa6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "anedya-widgets-react", - "version": "5.5.0", + "name": "@anedyasystems/anedya-widgets-react", + "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "anedya-widgets-react", - "version": "5.5.0", + "name": "@anedyasystems/anedya-widgets-react", + "version": "0.0.1", "license": "ISC", "dependencies": { "@anedyasystems/anedya-frontend-sdk": "^0.1.1", @@ -191,6 +191,29 @@ "win32" ] }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", @@ -1495,7 +1518,6 @@ "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2231,7 +2253,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -2908,7 +2929,6 @@ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -2939,7 +2959,6 @@ "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -2950,7 +2969,6 @@ "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -2987,7 +3005,6 @@ "integrity": "sha512-u7tgm5l4Yw1iTqUL4EcYOAt7fFvCgQMLeidrnD4GALlC6aOznCjezYajgxeyKw27u0Q5N7fwgCzjVyPIWzwuBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@oxc-project/types": "=0.140.0", "@rolldown/pluginutils": "^1.0.0" @@ -3255,7 +3272,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index bcaac123..22f91783 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "anedya-widgets-react", - "version": "5.5.0", + "name": "@anedyasystems/anedya-widgets-react", + "version": "0.0.1", "description": "Anedya widget SDK", "main": "dist/index.js", "module": "dist/index.mjs", From 7c403a20d5d535ad55995e3a03fbf0c3c9629924 Mon Sep 17 00:00:00 2001 From: surajmaurya-git Date: Tue, 28 Jul 2026 16:40:18 +0530 Subject: [PATCH 63/66] Remove fully configured AnedyaGauge example from App component --- examples/application-example/src/App.jsx | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/examples/application-example/src/App.jsx b/examples/application-example/src/App.jsx index 6680720f..efcda634 100644 --- a/examples/application-example/src/App.jsx +++ b/examples/application-example/src/App.jsx @@ -155,27 +155,6 @@ export default function App() { * ---------------------------------------------------------------- */} - {/* ---------------------------------------------------------------- - * 2.3 Full arc/track/needle/color/tick configuration, plus a - * custom theme. Demonstrates most visual knobs at once. - * ---------------------------------------------------------------- */} - - - {/* ---------------------------------------------------------------- * 2.4 onDataChange β€” same pattern as AnedyaCard: conditional * overrides (title, color, needle color, track color, animation From 3f443784eac20cc2b6a72a914976ccc22ebecf05 Mon Sep 17 00:00:00 2001 From: surajmaurya-git Date: Tue, 28 Jul 2026 17:14:23 +0530 Subject: [PATCH 64/66] chore: update package.json for changesets integration and add CI workflows - Added changeset scripts to package.json for versioning and changelog management. - Introduced .changeset directory with README, config, and initial changeset file. - Created CI workflow (ci.yml) to validate code quality on PRs and pushes to develop. - Established unified publish workflow (publish.yml) for beta and stable npm publishing. - Configured npm Trusted Publishing with OIDC for secure publishing without long-lived tokens. --- .changeset/README.md | 8 + .changeset/config.json | 11 + .changeset/thirty-candies-notice.md | 5 + .github/workflows/ci.yml | 65 ++ .github/workflows/publish.yml | 305 ++++++++ .gitignore | 3 + package-lock.json | 1130 ++++++++++++++++++++++++++- package.json | 24 +- 8 files changed, 1536 insertions(+), 15 deletions(-) create mode 100644 .changeset/README.md create mode 100644 .changeset/config.json create mode 100644 .changeset/thirty-candies-notice.md create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/publish.yml diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 00000000..654c6d47 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets). + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md). diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 00000000..5c58ec9f --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.1.4/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.changeset/thirty-candies-notice.md b/.changeset/thirty-candies-notice.md new file mode 100644 index 00000000..0a4bc6e7 --- /dev/null +++ b/.changeset/thirty-candies-notice.md @@ -0,0 +1,5 @@ +--- +"@anedyasystems/anedya-widgets-react": patch +--- + +anedya-widgets-react beta diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..adeda5c9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,65 @@ +# ───────────────────────────────────────────────────────────────────────────── +# CI Workflow +# +# PURPOSE: +# Validate code quality on every Pull Request and on pushes to `develop`. +# This workflow NEVER publishes to npm β€” it is a pure gate workflow. +# +# TRIGGERS: +# - Any pull_request (any base branch) +# - Direct pushes to `develop` (integration branch) +# +# WHY NOT prerelease / main? +# Those branches have their own dedicated publish workflows (prerelease.yml, +# release.yml) which already include all validation steps before publishing. +# Running ci.yml on those branches would create a redundant, competing job +# and could cause confusing workflow interleaving. +# ───────────────────────────────────────────────────────────────────────────── +name: CI + +on: + pull_request: + push: + branches: + - develop + +# Cancel any in-progress run for the same branch/PR so stale runs don't +# consume minutes and don't produce misleading status checks. +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: Lint Β· Typecheck Β· Build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js (LTS) + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + # npm ci is preferred over npm install in CI: + # - It is deterministic (uses package-lock.json exactly) + # - It deletes node_modules before installing, preventing stale deps + # - It fails if package-lock.json is out of sync with package.json + - name: Install Dependencies + run: npm ci + + # - name: Lint + # run: npm run lint + + - name: Typecheck + run: npm run typecheck + + - name: Build SDK + run: npm run build + + # Tests are not yet added β€” re-enable this step when test coverage lands. + # - name: Run Tests + # run: npm test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..2dffe4e8 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,305 @@ +# ───────────────────────────────────────────────────────────────────────────── +# Unified Publish Workflow (publish.yml) +# +# PURPOSE: +# Single workflow that handles BOTH beta and stable npm publishing using +# npm Trusted Publishing (OIDC) β€” no long-lived NPM_TOKEN required. +# +# WHY ONE FILE: +# npm allows only ONE Trusted Publisher configuration per package at a time, +# and validates against the CALLING workflow filename. Having two separate +# files (prerelease.yml + release.yml) means only one can be the trusted +# publisher at any given time. Merging into a single file solves this: +# configure npm trusted publisher with just `publish.yml`. +# +# TRIGGERS: +# - Push to `prerelease` β†’ publishes beta (dist-tag: beta) +# - Push to `main` β†’ publishes stable (dist-tag: latest) +# ci.yml remains separate and handles PRs + develop (no publish). +# +# TRUSTED PUBLISHING (OIDC) β€” HOW IT WORKS: +# 1. GitHub generates a short-lived OIDC token for this specific run. +# 2. npm validates: "Is this token from the configured trusted publisher?" +# (org=anedyaio, repo=anedya-widgets-react, workflow=publish.yml) +# 3. If yes β†’ npm issues a scoped, time-limited publish token automatically. +# 4. npm CLI (>=11.5.1) exchanges this and publishes without any secret. +# +# Requirements: +# βœ“ id-token: write permission +# βœ“ registry-url set in setup-node +# βœ“ npm >= 11.5.1 (auto-detects OIDC environment) +# βœ“ Node >= 22.14.0 +# βœ“ Public repository (provenance attestations generated automatically) +# +# CHANGESETS BRANCH LOGIC: +# prerelease branch: +# - Enters `changeset pre enter beta` if not already in pre mode +# - `changeset version` β†’ X.Y.Z-beta.N +# - `changeset publish` β†’ auto-uses `beta` dist-tag (from pre.json) +# +# main branch: +# - Exits pre mode (`changeset pre exit`) if pre.json is present +# - `changeset version` β†’ clean X.Y.Z +# - `changeset publish` β†’ `latest` dist-tag (npm default) +# - Creates git tag + GitHub Release +# +# PERMISSIONS: +# contents: write β†’ push version bump commits + tags +# id-token: write β†’ generate OIDC token for npm Trusted Publishing +# ───────────────────────────────────────────────────────────────────────────── +name: Publish + +on: + push: + branches: + - prerelease + - main + +concurrency: + # Separate concurrency groups per branch so a main push doesn't cancel + # an in-progress prerelease publish and vice versa. + group: publish-${{ github.ref }} + cancel-in-progress: false # Never cancel an in-progress publish run + +permissions: + contents: write + id-token: write # Required for npm Trusted Publishing (OIDC) + +jobs: + publish: + name: >- + ${{ github.ref == 'refs/heads/prerelease' && 'Prerelease Β· Beta' || 'Release Β· Stable' }} + runs-on: ubuntu-latest + + steps: + # ── 1. CHECKOUT ────────────────────────────────────────────────────────── + # fetch-depth: 0 gives Changesets full git history so it can determine + # which packages changed and what version bump type is needed. + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # ── 2. NODE SETUP ───────────────────────────────────────────────────────── + # registry-url MUST be set. setup-node writes an .npmrc that points + # NODE_AUTH_TOKEN (or the OIDC-exchanged token) to this registry. + # Without it, npm will not perform the OIDC token exchange. + - name: Setup Node.js (LTS) + uses: actions/setup-node@v4 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + cache: npm + + # ── 3. NPM UPGRADE ──────────────────────────────────────────────────────── + # Node 22 ships with npm 10.x by default. + # Trusted Publishing requires npm >= 11.5.1 to auto-detect OIDC environments. + # + # PINNED (not @latest): npm@latest is non-deterministic across CI runs. + # A newer npm@latest broke the `sigstore` dependency inside libnpmpublish, + # causing MODULE_NOT_FOUND errors during provenance generation. + # Pin to a known-good version. Update deliberately when needed. + - name: Upgrade npm (required for Trusted Publishing β‰₯ 11.5.1) + run: npm install -g npm@11.5.1 + + # ── 4. INSTALL DEPENDENCIES ─────────────────────────────────────────────── + - name: Install Dependencies + run: npm ci + + # ── 5. GIT IDENTITY ─────────────────────────────────────────────────────── + # Required so that version bump commits created by this workflow have a + # valid author when pushed back to the branch. + - name: Configure Git Identity + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + # ═════════════════════════════════════════════════════════════════════════ + # PRERELEASE BRANCH STEPS (only when push is to `prerelease`) + # ═════════════════════════════════════════════════════════════════════════ + + # ── 6a. ENTER PRE MODE ─────────────────────────────────────────────────── + # Enters Changesets prerelease mode only once. Once pre.json is committed + # back to the branch, subsequent runs skip this step automatically. + # `changeset version` in pre mode produces: X.Y.Z-beta.0, X.Y.Z-beta.1 … + - name: Enter Prerelease Mode (if not already active) + if: github.ref == 'refs/heads/prerelease' + run: | + if [ ! -f .changeset/pre.json ]; then + echo "::notice::Entering Changesets prerelease mode (beta)" + npx changeset pre enter beta + git add .changeset/pre.json + git commit -m "chore(release): enter prerelease mode [skip ci]" + git push origin prerelease + else + echo "::notice::Already in prerelease mode β€” skipping" + fi + + # ═════════════════════════════════════════════════════════════════════════ + # MAIN BRANCH STEPS (only when push is to `main`) + # ═════════════════════════════════════════════════════════════════════════ + + # ── 6b. EXIT PRE MODE ──────────────────────────────────────────────────── + # When `prerelease` is merged into `main`, pre.json arrives with the merge. + # We must exit pre mode so `changeset version` produces a clean stable + # version (e.g., 1.2.0 instead of 1.2.0-beta.3). + - name: Exit Prerelease Mode (if active) + if: github.ref == 'refs/heads/main' + run: | + if [ -f .changeset/pre.json ]; then + echo "::notice::Exiting Changesets prerelease mode" + npx changeset pre exit + git add .changeset/pre.json || true + else + echo "::notice::Not in prerelease mode β€” skipping" + fi + + # ═════════════════════════════════════════════════════════════════════════ + # SHARED STEPS (run for both prerelease and main) + # ═════════════════════════════════════════════════════════════════════════ + + # ── 7. VERSION PACKAGES ────────────────────────────────────────────────── + # Reads pending changeset files and updates package.json + CHANGELOG.md. + # In pre mode: appends -beta.N suffix. On main: produces clean X.Y.Z. + # If no changeset files exist, this is a no-op (exits cleanly). + - name: Version Packages + run: npx changeset version + + # ── 8. PUBLISH GATE ────────────────────────────────────────────────────── + # Only build + publish if package.json was actually modified. + # Prevents publishing when there are no pending changesets (e.g., a + # docs-only push with no changeset file added). + - name: Check for Version Changes + id: version_check + run: | + if git diff --quiet package.json; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "::notice::No changesets found β€” nothing to publish" + else + VERSION=$(node -p "require('./package.json').version") + echo "changed=true" >> "$GITHUB_OUTPUT" + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "::notice::Version bumped to $VERSION" + fi + + # ── 9. BUILD ───────────────────────────────────────────────────────────── + - name: Build SDK + if: steps.version_check.outputs.changed == 'true' + run: npm run build + + # Tests are disabled until test coverage lands. Re-enable when ready: + # - name: Run Tests + # if: steps.version_check.outputs.changed == 'true' + # run: npm test + + # ── 10. PUBLISH (OIDC β€” NO TOKEN NEEDED) ───────────────────────────────── + # npm CLI β‰₯ 11.5.1 automatically detects the OIDC environment (id-token: write + # permission + registry-url set). It exchanges the GitHub OIDC token for a + # short-lived, scoped publish token and publishes. + # + # Dist-tag logic (automatic, no --tag flag needed): + # - prerelease branch β†’ Changesets reads pre.json β†’ uses `beta` dist-tag + # - main branch β†’ no pre.json β†’ uses `latest` dist-tag (npm default) + # + # DO NOT add NODE_AUTH_TOKEN here β€” OIDC handles authentication entirely. + - name: Publish to npm + if: steps.version_check.outputs.changed == 'true' + run: npx changeset publish + + # ═════════════════════════════════════════════════════════════════════════ + # PRERELEASE BRANCH β€” POST-PUBLISH (push version bump back to branch) + # ═════════════════════════════════════════════════════════════════════════ + + - name: Commit and Push Prerelease Version Bump + if: >- + steps.version_check.outputs.changed == 'true' && + github.ref == 'refs/heads/prerelease' + run: | + git add -A + git commit -m "chore(release): v${{ steps.version_check.outputs.version }} prerelease [skip ci]" + git push origin prerelease --follow-tags + + # ═════════════════════════════════════════════════════════════════════════ + # MAIN BRANCH β€” POST-PUBLISH (commit, push, GitHub Release) + # ═════════════════════════════════════════════════════════════════════════ + + # NOTE: No explicit `git tag` step needed here. + # `changeset publish` already creates a `v{version}` tag locally because + # this is a single-package (root-type) repo β€” Changesets uses the format + # `v${version}` for root repos, not `${name}@${version}`. + # `--follow-tags` below pushes that tag to GitHub automatically. + # - name: Create Stable Version Tag + # if: >- + # steps.version_check.outputs.changed == 'true' && + # github.ref == 'refs/heads/main' + # run: | + # git tag -a "v${{ steps.version_check.outputs.version }}" \ + # -m "Release v${{ steps.version_check.outputs.version }}" + + - name: Commit and Push Stable Release + if: >- + steps.version_check.outputs.changed == 'true' && + github.ref == 'refs/heads/main' + run: | + git add -A + git commit -m "chore(release): v${{ steps.version_check.outputs.version }} [skip ci]" + git push origin main --follow-tags + + # Extract the latest CHANGELOG section to use as GitHub Release body. + # awk prints lines between the first and second `## ` headings. + - name: Extract Changelog for Release Notes + if: >- + steps.version_check.outputs.changed == 'true' && + github.ref == 'refs/heads/main' + id: extract_changelog + run: | + NOTES=$(awk '/^## /{if(found) exit; found=1; next} found{print}' CHANGELOG.md) + { + echo "notes<> "$GITHUB_OUTPUT" + + - name: Create GitHub Release + if: >- + steps.version_check.outputs.changed == 'true' && + github.ref == 'refs/heads/main' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "v${{ steps.version_check.outputs.version }}" \ + --title "v${{ steps.version_check.outputs.version }}" \ + --notes "${{ steps.extract_changelog.outputs.notes }}" \ + --target main + + # ── 11. SYNC MAIN BACK TO DEVELOP ──────────────────────────────────────── + # Merges the stable release changes and tag updates back into develop. + # Falls back to creating a Pull Request if develop is a protected branch. + - name: Sync Main back to Develop + if: >- + steps.version_check.outputs.changed == 'true' && + github.ref == 'refs/heads/main' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + echo "::notice::Attempting to merge main back into develop..." + + # Fetch the latest develop branch + git fetch origin develop + git checkout develop + + # Merge main (which contains the new version bump and changelog) + git merge main --no-edit + + # Try to push directly (works if develop is not protected) + if git push origin develop; then + echo "::notice::Successfully merged and pushed main back to develop directly!" + else + echo "::warning::Direct push to develop was blocked. Creating a Pull Request instead..." + git checkout main + gh pr create \ + --base develop \ + --head main \ + --title "chore(release): sync main v${{ steps.version_check.outputs.version }} to develop" \ + --body "Automated PR to sync develop with the stable release v${{ steps.version_check.outputs.version }}." || true + fi diff --git a/.gitignore b/.gitignore index 193a6ea7..54eef41c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ yarn-error.log* test/ dist/ +documents/ +development/ +deployment/package-development.md diff --git a/package-lock.json b/package-lock.json index 68f19fa6..9558bed1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@base-ui/react": "^1.6.0", + "@changesets/cli": "^2.31.1", "@tailwindcss/cli": "^4.3.3", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", @@ -191,6 +192,248 @@ "win32" ] }, + "node_modules/@changesets/apply-release-plan": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.1.1.tgz", + "integrity": "sha512-9qPCm/rLx/xoOFXIHGB229+4GOL76S4MC+7tyOuTsR6+1jYlfFDQORdvwR5hDA6y4FL2BPt3qpbcQIS+dW85LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/config": "^3.1.4", + "@changesets/get-version-range-type": "^0.4.0", + "@changesets/git": "^3.0.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-6.0.10.tgz", + "integrity": "sha512-rSDcqdJ9KbVyjpBIuCidhvZNIiVt1XaIYp73ycVQRIA5n/j6wQaEk0ChRLMUQ1vkxZe51PTQ9OIhbg6HQMW45A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.4", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.2.1.tgz", + "integrity": "sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.31.1", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.31.1.tgz", + "integrity": "sha512-uO05WTcRBwuVOJVSW8Cmpqw6q0WDL53ajGCMyszutvOe5toOnunbpM4jZzf+qxBOz7i0AzopZ8diBuewjmF40w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/apply-release-plan": "^7.1.1", + "@changesets/assemble-release-plan": "^6.0.10", + "@changesets/changelog-git": "^0.2.1", + "@changesets/config": "^3.1.4", + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.4", + "@changesets/get-release-plan": "^4.0.16", + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@changesets/write": "^0.4.0", + "@inquirer/external-editor": "^1.0.2", + "@manypkg/get-packages": "^1.1.3", + "ansi-colors": "^4.1.3", + "enquirer": "^2.4.1", + "fs-extra": "^7.0.1", + "mri": "^1.2.0", + "package-manager-detector": "^0.2.0", + "picocolors": "^1.1.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^3.0.1", + "term-size": "^2.1.0" + }, + "bin": { + "changeset": "bin.js" + } + }, + "node_modules/@changesets/config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-3.1.4.tgz", + "integrity": "sha512-pf0bvD/v6WI2cRlZ6hzpjtZdSlXDXMAJ+Iz7xfFzV4ZxJ8OGGAON+1qYc99ZPrijnt4xp3VGG7eNvAOGS24V1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/get-dependents-graph": "^2.1.4", + "@changesets/logger": "^0.1.1", + "@changesets/should-skip-package": "^0.1.2", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.8" + } + }, + "node_modules/@changesets/errors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.2.0.tgz", + "integrity": "sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==", + "dev": true, + "license": "MIT", + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-2.1.4.tgz", + "integrity": "sha512-ZsS00x6WvmHq3sQv8oCMwL0f/z3wbXCVuSVTJwCnnmbC/iBdNJGFx1EcbMG4PC6sXRyH69liM4A2WKXzn/kRPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "picocolors": "^1.1.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-4.0.16.tgz", + "integrity": "sha512-2K5Om6CrMPm45rtvckfzWo7e9jOVCKLCnXia5eUPaURH7/LWzri7pK1TycdzAuAtehLkW7VPbWLCSExTHmiI6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/assemble-release-plan": "^6.0.10", + "@changesets/config": "^3.1.4", + "@changesets/pre": "^2.0.2", + "@changesets/read": "^0.6.7", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.4.0.tgz", + "integrity": "sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-3.0.4.tgz", + "integrity": "sha512-BXANzRFkX+XcC1q/d27NKvlJ1yf7PSAgi8JG6dt8EfbHFHi4neau7mufcSca5zRhwOL8j9s6EqsxmT+s+/E6Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.8", + "spawndamnit": "^3.0.1" + } + }, + "node_modules/@changesets/logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.1.1.tgz", + "integrity": "sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.4.3.tgz", + "integrity": "sha512-ZDmNc53+dXdWEv7fqIUSgRQOLYoUom5Z40gmLgmATmYR9NbL6FJJHwakcCpzaeCy+1D0m0n7mT4jj2B/MQPl7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "js-yaml": "^4.1.1" + } + }, + "node_modules/@changesets/pre": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-2.0.2.tgz", + "integrity": "sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/errors": "^0.2.0", + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.6.7.tgz", + "integrity": "sha512-D1G4AUYGrBEk8vj8MGwf75k9GpN6XL3wg8i42P2jZZwFLXnlr2Pn7r9yuQNbaMCarP7ZQWNJbV6XLeysAIMhTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/git": "^3.0.4", + "@changesets/logger": "^0.1.1", + "@changesets/parse": "^0.4.3", + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0", + "picocolors": "^1.1.0" + } + }, + "node_modules/@changesets/should-skip-package": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@changesets/should-skip-package/-/should-skip-package-0.1.2.tgz", + "integrity": "sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-6.1.0.tgz", + "integrity": "sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@changesets/write": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.4.0.tgz", + "integrity": "sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@changesets/types": "^6.1.0", + "fs-extra": "^7.0.1", + "human-id": "^4.1.1", + "prettier": "^2.7.1" + } + }, "node_modules/@emnapi/core": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", @@ -267,6 +510,45 @@ "dev": true, "license": "MIT" }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -317,6 +599,71 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@manypkg/find-root/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", @@ -336,6 +683,44 @@ "@emnapi/runtime": "^1.7.1" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@oxc-project/types": { "version": "0.140.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.140.0.tgz", @@ -1512,6 +1897,13 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", @@ -1847,6 +2239,26 @@ "dev": true, "license": "MIT" }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/ansis": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.3.1.tgz", @@ -1857,6 +2269,36 @@ "node": ">=14" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/braces": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", @@ -1911,6 +2353,13 @@ "cbor-extract": "^2.2.2" } }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -1929,6 +2378,21 @@ "node": ">= 10" } }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -2353,6 +2817,16 @@ "robust-predicates": "^3.0.2" } }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -2366,6 +2840,19 @@ "node": ">=0.10" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dts-resolver": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-3.0.0.tgz", @@ -2411,6 +2898,68 @@ "node": ">=10.13.0" } }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -2445,10 +2994,39 @@ "node": ">=8" } }, - "node_modules/get-tsconfig": { - "version": "5.0.0-beta.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", - "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/get-tsconfig": { + "version": "5.0.0-beta.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-5.0.0-beta.5.tgz", + "integrity": "sha512-/6gFNr0N04nob252sTQxyFLi3eKFRqIg1I87YcqAMT1i6SQrSF6KujUEQrtrjMV0H/eejTCltLdDSTEMzHbnsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2461,6 +3039,40 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -2475,6 +3087,16 @@ "dev": true, "license": "MIT" }, + "node_modules/human-id": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-4.2.0.tgz", + "integrity": "sha512-K3GbkIWqyvvlpfhBPlbEvD97TtqBpAYA4kt+cn2lD2x2HuohzZCibcA2nOlnJT6exqvJLggoB5nv2dNf192nEA==", + "dev": true, + "license": "MIT", + "bin": { + "human-id": "dist/cli.js" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -2487,6 +3109,16 @@ "node": ">=0.10.0" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/import-without-cache": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/import-without-cache/-/import-without-cache-0.4.0.tgz", @@ -2542,6 +3174,36 @@ "node": ">=0.12.0" } }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", @@ -2552,6 +3214,39 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-yaml": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -2823,6 +3518,26 @@ "node": ">=8" } }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true, + "license": "MIT" + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -2833,6 +3548,16 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -2916,6 +3641,132 @@ "node": ">=12.20.0" } }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-manager-detector": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", + "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quansync": "^0.2.7" + } + }, + "node_modules/package-manager-detector/node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -2936,6 +3787,32 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/quansync": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", @@ -2953,6 +3830,27 @@ ], "license": "MIT" }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/react": { "version": "19.2.8", "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", @@ -2976,6 +3874,46 @@ "react": "^19.2.8" } }, + "node_modules/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/read-yaml-file/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/read-yaml-file/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/reselect": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", @@ -2983,6 +3921,16 @@ "dev": true, "license": "MIT" }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -2993,6 +3941,17 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/robust-predicates": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", @@ -3075,6 +4034,30 @@ } } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rw": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", @@ -3094,6 +4077,65 @@ "dev": true, "license": "MIT" }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3104,6 +4146,47 @@ "node": ">=0.10.0" } }, + "node_modules/spawndamnit": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-3.0.1.tgz", + "integrity": "sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==", + "dev": true, + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "cross-spawn": "^7.0.5", + "signal-exit": "^4.0.1" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/tailwind-merge": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", @@ -3135,6 +4218,19 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tinyexec": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", @@ -3294,6 +4390,16 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", @@ -3317,6 +4423,22 @@ "url": "https://github.com/sponsors/sxzz" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/yuku-ast": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/yuku-ast/-/yuku-ast-0.7.4.tgz", diff --git a/package.json b/package.json index 22f91783..362fee10 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Anedya widget SDK", "main": "dist/index.js", "module": "dist/index.mjs", - "type": "module", + "type": "module", "types": "dist/index.d.ts", "files": [ "dist" @@ -21,16 +21,17 @@ "types": "./dist/formatters.d.mts" } }, -"scripts": { - "clean": "rm -rf dist", -"build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/styles.css --minify", - "build:js": "tsdown", - "build": "npm run clean && npm run build:js && npm run build:css", - "dev": "npm run clean && tsdown --watch", - "typecheck": "tsc --noEmit" -}, - - + "scripts": { + "clean": "rm -rf dist", + "build:css": "tailwindcss -i ./src/styles/base.css -o ./dist/styles.css --minify", + "build:js": "tsdown", + "build": "npm run clean && npm run build:js && npm run build:css", + "dev": "npm run clean && tsdown --watch", + "typecheck": "tsc --noEmit", + "changeset": "changeset", + "changeset:status": "changeset status", + "changeset:version": "changeset version" + }, "repository": { "type": "git", "url": "https://github.com/anedyaio/anedya-widgets-react" @@ -53,6 +54,7 @@ }, "devDependencies": { "@base-ui/react": "^1.6.0", + "@changesets/cli": "^2.31.1", "@tailwindcss/cli": "^4.3.3", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", From e7070a95f6e5da85180d3a57349fb70e833b4399 Mon Sep 17 00:00:00 2001 From: surajmaurya-git Date: Tue, 28 Jul 2026 17:24:29 +0530 Subject: [PATCH 65/66] refactor: update CI job name and clean up package-lock.json dependencies --- .github/workflows/ci.yml | 2 +- package-lock.json | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adeda5c9..db92d485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ concurrency: jobs: validate: - name: Lint Β· Typecheck Β· Build + name: Typecheck Β· Build runs-on: ubuntu-latest steps: diff --git a/package-lock.json b/package-lock.json index 9558bed1..ff07768b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -612,6 +612,13 @@ "fs-extra": "^8.1.0" } }, + "node_modules/@manypkg/find-root/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@manypkg/find-root/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -1897,13 +1904,6 @@ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, - "node_modules/@types/node": { - "version": "12.20.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", - "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/react": { "version": "19.2.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", From f5edaee930e0693a6d35367f37fb3accb0b60d5a Mon Sep 17 00:00:00 2001 From: surajmaurya-git Date: Tue, 28 Jul 2026 17:31:58 +0530 Subject: [PATCH 66/66] chore: restore tsconfig.json with compiler options for TypeScript --- ts.config.json => tsconfig.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ts.config.json => tsconfig.json (100%) diff --git a/ts.config.json b/tsconfig.json similarity index 100% rename from ts.config.json rename to tsconfig.json