diff --git a/samples/chart-widget/README.md b/samples/chart-widget/README.md new file mode 100644 index 0000000..47af22b --- /dev/null +++ b/samples/chart-widget/README.md @@ -0,0 +1,156 @@ +# ChartJS Widget + +A sample widget that displays an SVG-based based on the [ChartJS package](https://www.chartjs.org/https:/). +The widget is completely programmable. It only supports one dataset. + +![](assets/20240422_185328_image.png) + +The widget is a **Display Widget**, so it does not hold data by itself but can be used to display data coming from other widgets. + +When the widget is instantiated at runtime, it gets a unique HTML ID following this convention: `chartJS_' + Date.now()`. + +## Widget Properties and events + +![](assets/20240424_095107_image.png) + +### Properties + +--- + +* **Enable Debug** + When set, verbose output is generated on the browser console + + ![](assets/20240423_181436_image.png) +* **Width** + + The *width* of the widget can be modified on respect to its default values. The *width* can be expressed as "**px**" or as "**percentage**". Please be sure to use the following format: + + * `px` when using "pixels" (for instance 100px or 50px...) + * `%`when using "percentage" (for instance 100% or 20%). The percentage is on respect to the grid cell containing the **chartJS widget**: thus `100%` means that the widget takes all the width of the grid cell. +* **Height** + The *height* of the widget can be modified on respect to its default values. The *height* can **only** be expressed as "**px**" or as "**percentage**". Please be sure to use the following format: + + * `px` when using "pixels" (for instance 100px or 50px...) + * `%` when using "percentage" (for instance 100% or 20%). The percentage is on respect to the grid cell containing the **chartJS widget**: thus `100%` means that the widget takes all the height of the grid cell. +* **Chart Type** + The form Author can chose among the following values from the droplist: + + * **Pie Chart** : the default + + ![](assets/20240423_182619_image.png) + * **Donut** + + ![](assets/20240423_182706_image.png) + * **Bar Chart** + + ![](assets/20240423_182747_image.png) + * **Line Chart** + + ![](assets/20240424_095302_image.png) + * **Polar** + + ![](assets/20240423_182916_image.png) +* **Labels** + This is a comma-separated list of strings which are assigned to the dataset. + The default is `"blue, red, orange, yellow, green, purple, grey"`. +* **Colors** + This is a comma-separated list of strings which are used to define the dataset colors. + The default is `"blue, red, orange, yellow, green, purple, grey"`. You can use the "text" representation of the color. + The colors will be re-used if the dataset counts more elements than the list of colors. For exemple: + + * if you want all the data to be drawn with the same color, then it will be enough to provide one single color in the list + * if you want two colors to be used alterntively for the data in the dataset, then the list should count only two colors +* **Dataset Label** + The data that are shown in the chart reference some real quantity. The **Dataset Label** is the label you want to associate to that quantity. + + * The label is, normally, visualized on hovering over each element, as shown in the image below (where the **Dataset Label** is `"The Value"`) : + + ![](assets/20240423_184937_image.png) + * the label is, also, shown on the top of the chart for the chart types **"Line Chart"** and **"Bar Chart"** as shown below (where the **Dataset Label** is `"The Value"`): + + ![](assets/20240424_112954_image.png) +* **OnHover Description** + A string that appears when the user passes the mouse "over" the widget + +### Events + +--- + +The widget honors the **click event**. In this way, the form Author can assign some custom behavior when the form User clicks on the widget. + +### Programming the ChartJS Widget + +--- + +The following APIs allow the Author to programmatically perform the following operations: + +- `getDisplayTitle() / setTitle(string)` + Gets and sets the title of the widget +- `getData() / setData(comma-separated list of strings)` + Gets the dataset values currently shown by the widget and Sets the dataset values shown by the widget +- `getLabels() / setLabels(comma-separated list of strings)` + Gets and sets the value of the **Labels** corresponding to dataset values shown by the widget +- `getDatasetLabel() / setDatasetLabel(cstring)` + Gets and sets the **Label** for to dataset shown by the widget +- `getColors() / setColors(comma-separated list of strings)` + Gets and sets the names of the **Colors** corresponding to dataset values shown by the widget +- `getChartType() / setChartType(string)` + Programmatically gets or set the current chart type. The values to be used are the following + + + | value | chart type | + | ----------- | :------------ | + | doughnut | Donut | + | pie | Pie Chart | + | bar | Bar Chart | + | line | Line Chart | + | polarArea | Polar Chart | +- `getChartTypes()` + Returns a comma-separated string listing all the available **Chart Types** (see previous table). +- `getWidth() / setWidth(string)` + Gets and sets the **width** of the **chartJS widget**. For the widget's **width**, please be sure to use the following format: + + - `px` when using "pixels" (for instance 100px or 50px...) + - `%` when using "percentage" (for instance 100% or 20%). The percentage is on respect to the grid cell containing the **chartJS widget**: thus `100%` means that the widget takes all the width of the grid cell. +- `getHeight() / setHeight(string)` + Gets and sets the **height** of the **chartJS widget**. For the widget's **height**, please be sure to use the following format: + + - `px` when using "pixels" (for instance 100px or 50px...) + - `%` when using "percentage" (for instance 100% or 20%). The percentage is on respect to the grid cell containing the **chartJS widget**: thus `100%` means that the widget takes all the height of the grid cell. +- `getDebugFlag() / setDebugFlag(boolean)` + Gets and sets the *Debug flag* for the widget instance + +## Build + +In case you need/want to modify and rebuild the widget, please follow these steps: + +1. Install `git` and `npm` (consult the internet) +2. Open git bash console +3. Clone this repo. For example: + `git clone https://github.com/HCL-TECH-SOFTWARE/leap-custom-widgets.git` +4. `cd leap-custom-widgets/samples/chart-widget` +5. `npm install` +6. `npm run build` + +The output of the build will be in the `dist/` directory. +If you wish to make code changes to the sample, use `npm build-watch` to have the files building continuously. Refresh the browser to see recent changes. + +## Run + +Take the `chartJS.js`and `chartJS.css` files from the `dist/`directory and and place them onto a web server. + +- **HCL Leap** configuration + Add the following to `Leap_config.properties`: + +```properties +ibm.nitro.NitroConfig.runtimeResources.1 = \ + \n\ + +``` + +- **HCL domino Leap** configuration + *HCL Domino Leap* configuration is done similarly by adding a config setting in `VoltConfig.nsf`. + +![](assets/20240422_180625_image.png) + +## Credits diff --git a/samples/chart-widget/assets/20240422_180625_image.png b/samples/chart-widget/assets/20240422_180625_image.png new file mode 100644 index 0000000..26e5f66 Binary files /dev/null and b/samples/chart-widget/assets/20240422_180625_image.png differ diff --git a/samples/chart-widget/assets/20240422_185328_image.png b/samples/chart-widget/assets/20240422_185328_image.png new file mode 100644 index 0000000..fe74672 Binary files /dev/null and b/samples/chart-widget/assets/20240422_185328_image.png differ diff --git a/samples/chart-widget/assets/20240423_181436_image.png b/samples/chart-widget/assets/20240423_181436_image.png new file mode 100644 index 0000000..14a50e9 Binary files /dev/null and b/samples/chart-widget/assets/20240423_181436_image.png differ diff --git a/samples/chart-widget/assets/20240423_182619_image.png b/samples/chart-widget/assets/20240423_182619_image.png new file mode 100644 index 0000000..93641b4 Binary files /dev/null and b/samples/chart-widget/assets/20240423_182619_image.png differ diff --git a/samples/chart-widget/assets/20240423_182706_image.png b/samples/chart-widget/assets/20240423_182706_image.png new file mode 100644 index 0000000..7f20c7d Binary files /dev/null and b/samples/chart-widget/assets/20240423_182706_image.png differ diff --git a/samples/chart-widget/assets/20240423_182747_image.png b/samples/chart-widget/assets/20240423_182747_image.png new file mode 100644 index 0000000..431776e Binary files /dev/null and b/samples/chart-widget/assets/20240423_182747_image.png differ diff --git a/samples/chart-widget/assets/20240423_182916_image.png b/samples/chart-widget/assets/20240423_182916_image.png new file mode 100644 index 0000000..a439e35 Binary files /dev/null and b/samples/chart-widget/assets/20240423_182916_image.png differ diff --git a/samples/chart-widget/assets/20240423_184937_image.png b/samples/chart-widget/assets/20240423_184937_image.png new file mode 100644 index 0000000..1857b9c Binary files /dev/null and b/samples/chart-widget/assets/20240423_184937_image.png differ diff --git a/samples/chart-widget/assets/20240424_095107_image.png b/samples/chart-widget/assets/20240424_095107_image.png new file mode 100644 index 0000000..9660351 Binary files /dev/null and b/samples/chart-widget/assets/20240424_095107_image.png differ diff --git a/samples/chart-widget/assets/20240424_095302_image.png b/samples/chart-widget/assets/20240424_095302_image.png new file mode 100644 index 0000000..cc46893 Binary files /dev/null and b/samples/chart-widget/assets/20240424_095302_image.png differ diff --git a/samples/chart-widget/assets/20240424_112954_image.png b/samples/chart-widget/assets/20240424_112954_image.png new file mode 100644 index 0000000..7d02ced Binary files /dev/null and b/samples/chart-widget/assets/20240424_112954_image.png differ diff --git a/samples/chart-widget/package-lock.json b/samples/chart-widget/package-lock.json new file mode 100644 index 0000000..e7e3706 --- /dev/null +++ b/samples/chart-widget/package-lock.json @@ -0,0 +1,1840 @@ +{ + "name": "hcl-leap-custom-widgets-chartjs", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hcl-leap-custom-widgets-chartjs", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "chart.js": "^4.4.1" + }, + "devDependencies": { + "copy-webpack-plugin": "^11.0.0", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz", + "integrity": "sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==" + }, + "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, + "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, + "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, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.5", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz", + "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "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 + }, + "node_modules/@types/node": { + "version": "20.11.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.27.tgz", + "integrity": "sha512-qyUZfMnCg1KEz57r7pzFtSGt49f6RPkPBis3Vo4PbS7roQEDn22hiHzl/Lo1q4i4hDEgBJmBF/NTNg2XR0HbFg==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "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" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", + "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" + } + ] + }, + "node_modules/chart.js": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.2.tgz", + "integrity": "sha512-6GD7iKwFpP5kbSD4MeRRRlTnQvxfQREy36uEtm1hzHzcOqwWx0YEHuspuoNlslu+nciLIB7fjjsHkUv/FzFcOg==", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.705", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.705.tgz", + "integrity": "sha512-LKqhpwJCLhYId2VVwEzFXWrqQI5n5zBppz1W9ehhTlfYU8CUUW6kClbN8LHF/v7flMgRdETS772nqywJ+ckVAw==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz", + "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/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, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "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 + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "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.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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 + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "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 + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "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, + "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, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.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 + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "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==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "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, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "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, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "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, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "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, + "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, + "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==", + "dev": true + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "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" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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" + } + ] + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", + "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/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 + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "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" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "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, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/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 + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "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, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + } + } +} diff --git a/samples/chart-widget/package.json b/samples/chart-widget/package.json new file mode 100644 index 0000000..861dcbd --- /dev/null +++ b/samples/chart-widget/package.json @@ -0,0 +1,19 @@ +{ + "name": "hcl-leap-custom-widgets-chartjs", + "description": "HCL Leap - ChartJS Widget", + "private": true, + "version": "0.1.0", + "license": "Apache-2.0", + "scripts": { + "build": "webpack", + "build-watch": "webpack --env watch=true" + }, + "dependencies": { + "chart.js": "^4.4.1" + }, + "devDependencies": { + "copy-webpack-plugin": "^11.0.0", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4" + } +} diff --git a/samples/chart-widget/src/chartJS.css b/samples/chart-widget/src/chartJS.css new file mode 100644 index 0000000..b57094e --- /dev/null +++ b/samples/chart-widget/src/chartJS.css @@ -0,0 +1,8 @@ +/* + Code for Donut Chart widget + =========================== +*/ +.flex-wrapper { + display: flex; + flex-flow: row nowrap; + } diff --git a/samples/chart-widget/src/chartJS.js b/samples/chart-widget/src/chartJS.js new file mode 100644 index 0000000..91367a1 --- /dev/null +++ b/samples/chart-widget/src/chartJS.js @@ -0,0 +1,428 @@ +import Chart from "chart.js/auto"; + +if (typeof leapSample === 'undefined') { + leapSample = {}; // use an isolated namespace +}; + + +leapSample.donutWidget = { + id: "leapSample.leap.sample.chartJS", + version: "1.0.0", + apiVersion: "1.0.0", + label: { + "default": "ChartJS Widget", + "it": "Esempio ChartJS Widget", + }, + description: { + "default": "Provides a way to create ChartJS chartsr", + "it": "Il nuovo ChartJS Widget", + "fr": "Le nouveau widget pour faire des chartsJS" + }, + category: { + id: "hcl.leap.sample.widgets", + label: { + "default": "ChartJS", + "it": "ChartJS", + } + }, + formPalette: true, + appPagePalette: true, + iconClassName: "checkmarkIcon", + builtInProperties: [{ + id: "title" + }, + { + id: "id", + }, + { + id: "customAttribute" + }, + { + id: "seenInOverview", + defaultValue: true + } + ], + properties: [ + { + id: "debugFlag", + propType: "boolean", + label: { + "default": "Enable Debug", + "it": "Abilita debug" + }, + defaultValue: { + "default": false + } + }, + { + id: "theWidth", + propType: "string", + label: { + "default": "Width (px or %)", + "it": "Larghezza (px o %)" + }, + defaultValue: "100%" + }, + { + id: "theHeight", + propType: "string", + label: { + "default": "Height (px or %)", + "it": "Altezza (px or %)" + }, + defaultValue: "100%" + }, + { + id: "chartType", + propType: 'enum', + values: [{title: 'Donut', value: 'doughnut'}, {title: 'Bar chart', value: 'bar'}, {title: 'Pie chart', value: 'pie'}, {title: 'Polar', value: 'polarArea'}, {title: 'Line chart', value: 'line'}], + label: { + "default": "Chart Type", + "it": "Tipo di Chart" + }, + defaultValue: "pie" + }, + { + id: "labels", + propType: "string", + label: { + "default": "Labels", + "it": "labels" + }, + defaultValue: "blue, red, orange, yellow, green, purple, grey" + }, + { + id: "colors", + propType: "string", + label: { + "default": "Colors", + "it": "Colori" + }, + defaultValue: "blue, red, orange, yellow, green, purple, grey" + }, + { + id: "datasetLabel", + propType: "string", + label: { + "default": "Dataset Label", + "it": "Etichetta Dataset" + }, + defaultValue: "The Value" + }, + { + id: "explanationText", + propType: "string", + label: { + "default": "OnHover Description", + "it": "Descrizione OnHover" + }, + defaultValue: "OnHover Text" + } + ], + + // initialize widget in the DOM, with initial properties and event callbacks + instantiate: function (context, domNode, initialProps, eventManager) { + let widgetInstance = { + _mode: null, + _flexNode: null, + _fieldsetNode: null, + _legendNode: null, + _debugFlag: true, + _theId: context.id, + _theCanvas: null, + _theChart: null, + _datasetLabel: null, + _chartType: null, + /** + * IMPORTANT: Avoids script injection + */ + _sanitizeHTML: function (str) { + let s = '' + str; + s = s.replace(/&/g, '&').replace(//g, '>').replace(/'/g, ''').replace(/"/g, '"'); + return s; + }, + _debugMsg: function(ctx, msg) { + if (ctx._debugFlag) console.log(ctx._theId + msg); + }, + // + // internal method for creating and initializing the widget + // + _init: function (context, domNode, initialProps, eventManager) { + if (initialProps.debugFlag && (initialProps.debugFlag === true)) console.log(JSON.stringify(initialProps, ' ', 4)); + this._mode = context.mode; + const isDisabled = this._mode === 'design'; + const groupName = this._sanitizeHTML(context.id); + + const widgetHTML = '' + + '
\n' + + ' \n' + + '
\n' + + ' \n' + + '
\n' + + '
'; + + domNode.innerHTML = widgetHTML; + this._fieldsetNode = domNode.firstChild; + this._legendNode = this._fieldsetNode.querySelector('legend'); + this._flexNode = this._fieldsetNode.querySelector('.flex-wrapper'); + this._theCanvas = this._flexNode.querySelector('canvas'); + this._theChart = new Chart(this._theCanvas, + { + type: 'doughnut', + data: { + labels: ['blue', 'red', 'orange', 'yellow', 'green', 'purple', 'grey'], + datasets: [{ + label: '# of Votes', + data: [12, 19, 3, 5, 2, 3, 8], + backgroundColor: ["red", "red", "red", "red", "red", "red", "red"], + borderWidth: 1 + }] + }, + options: { + scales: { + y: { + beginAtZero: true + } + } + } + }); + // + // set initial prop values + // + Object.keys(initialProps).forEach((propName) => { + this._setProp({propName: propName, propValue: initialProps[propName]}); + }); + // + // propagate events + // + this._theCanvas.addEventListener("click", () => { + this._debugMsg(this, '.clickListener: CLICK EVENT'); + eventManager.sendEvent('onClick'); + }); +/* + this._theCanvas.addEventListener("input", function() { + // will trigger call to getValue() + // this._debugMsg(this, '.changeListener: CHANGE EVENT'); + //eventManager.sendEvent('onChange'); + }); + this._theCanvas.addEventListener("focus", () => { + //ithis._debugMsg(this, '.changeListener: FOCUS EVENT'); + //eventManager.sendEvent('onFocus'); + }); + this._theCanvas.addEventListener("blur", () => { + //this._debugMsg(this, '.changeListener: BLUR EVENT'); + //eventManager.sendEvent('onBlur'); + }); + this._theCanvas.addEventListener("mouseover", () => { + //ithis._debugMsg(this, '.changeListener: MOUSEOVER EVENT'); + //alert('INPUT ' + this._valueNode.value); + //if (this._debugFlag) console.log(this._valueNode); + //eventManager.sendEvent('onMouseOver'); + }); + this._theCanvas.addEventListener("mouseout", () => { + //this._debugMsg(this, '.changeListener: MOUSEOUT EVENT'); + //eventManager.sendEvent('onMouseOut'); + }); + */ + }, + // internal custom mechanics for changing widget props + _setProp: function ({propName, propValue}) { + this._debugMsg(this, '._setProp: Setting ' + propName + ' to ' + propValue); + switch (propName) { + case "title": + this._legendNode.innerHTML = this._sanitizeHTML(propValue); + break; + case "explanationText": + this._fieldsetNode.setAttribute('title', this._sanitizeHTML(propValue)); + break; + case "theWidth": + this._theCanvas.style["width"] = this._sanitizeHTML(propValue); + break; + case "theHeight": + this._theCanvas.style["height"] = this._sanitizeHTML(propValue); + break; + case "chartType": + this._chartType = this._sanitizeHTML(propValue); + this._theChart.config.type = this._chartType; + if (this._chartType === 'polarArea') { + delete(this._theChart.config.options.scales.y); + this._theChart.config.options.scales.r = {beginAtZero: true}; + } else { + delete(this._theChart.config.options.scales.r); + this._theChart.config.options.scales.y = {beginAtZero: true}; + } + if (this._chartType === 'line') { + this._theChart.config.data.datasets[0].borderWidth = 7; + } else { + this._theChart.config.data.datasets[0].borderWidth = 1; + } + this._theChart.update(); + break; + case "data": + if (!Array.isArray(propValue)) { + propValue = propValue.replace(/\s/g, ''); + propValue = propValue.split(','); + } + this._debugMsg(this, '._setProp: data to ' + propValue); + this._theChart.config.data.datasets[0].data = propValue; + this._theChart.update(); + break; + case "labels": + if (!Array.isArray(propValue)) { + // + // Transform to Array + // + propValue = propValue.replace(/\s/g, ''); + propValue = propValue.split(','); + } + this._debugMsg(this, '._setProp: labels to ' + propValue); + if (propValue.join(',') === this._theChart.config.data.labels.join(',')) { + // + // nothing changed + // + this._debugMsg(this, '._setProp: labels : NOTHING to set. Same value'); + } else { + // + // Changing... + // + this._theChart.config.data.labels = propValue; + this._theChart.update(); + } + break; + case "colors": + if (!Array.isArray(propValue)) { + // + // Transform to Array + // + propValue = propValue.replace(/\s/g, ''); + propValue = propValue.split(','); + } + this._debugMsg(this, '._setProp: colors to ' + propValue); + if (propValue.join(',') === this._theChart.config.data.datasets[0].backgroundColor.join(',')) { + // + // nothing changed + // + this._debugMsg(this, '._setProp: labels : NOTHING to set. Same value'); + } else { + // + // Changing... + // + this._theChart.config.data.datasets[0].backgroundColor = propValue; + this._theChart.update(); + } + break; + case "datasetLabel": + this._datasetLabel = this._sanitizeHTML(propValue); + this._theChart.config.data.datasets[0].label = this._datasetLabel; + this._theChart.update(); + break; + case "debugFlag": + this._debugFlag = propValue; + break; + default: + // ignore + break; + } + }, + // + // for display in various parts of the UI + // + getDisplayTitle: function () { + this._debugMsg(this, '.getDisplayTitle : ' + this._legendNode.innerHTML); + return this._legendNode.innerHTML; + }, + // + // called when properties change in the authoring environment, or via JavaScript API + // + setProperty: function (propName, propValue) { + this._debugMsg(this, '.setProperty ' + propName + ' to ' + propValue); + this._setProp({propName, propValue}); + }, + // + // determines what the author can do with the widget via custom JavaScript + // + getJSAPIFacade: function () { + this._debugMsg(this, '.getJSAPIFacade: defining FACADE'); + const facade = { + __self: this, // double-underscore keeps this private + setTitle: function (theTitle) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setTitle : ' + theTitle); + this.__self._setProp({propName: 'title', propValue: theTitle}); + }, + setWidth: function(theWidth) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setWidth to ' + theWidth); + this.__self._setProp({propName: 'theWidth', propValue: theWidth}); + }, + getWidth: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getWidth to ' + this.__self._theCanvas.style["width"]); + return this.__self._theCanvas.style["width"]; + }, + setHeight: function(theHeight) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setHeight to ' + theHeight); + this.__self._setProp({propName: 'theHeight', propValue: theHeight}); + }, + getHeight: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getHeight to ' + this.__self._theCanvas.style["height"]); + return this.__self._theCanvas.style["height"]; + }, + setChartType: function(theType) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setChartType to ' + theType); + this.__self._setProp({propName: 'chartType', propValue: theType}); + }, + getChartType: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getChartType for ' + this.__self._chartType); + return this.__self._chartType; + }, + getChartTypes: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getChartTypes for ....'); + return [{title: 'Donut', value: 'doughnut'}, {title: 'Bar chart', value: 'bar'}, {title: 'Pie chart', value: 'pie'}, {title: 'Polar', value: 'polarArea'}, {title: 'Line chart', value: 'line'}]; + }, + setData: function (dataArray) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setData to ' + dataArray); + this.__self._setProp({propName: 'data', propValue: dataArray}); + }, + getData: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getData for ' + this.__self._theChart.config.data.datasets[0].data.join(',')); + return this.__self._theChart.config.data.datasets[0].data; + }, + setLabels: function (labelsArray) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setLabels to ' + labelsArray); + this.__self._setProp({propName: 'labels', propValue: labelsArray}); + }, + geLabels: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getLabels for ' + this.__self._theChart.config.data.labels.join(',')); + return this.__self._theChart.config.data.labels; + }, + setColors: function (labelsArray) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setColors to ' + labelsArray); + this.__self._setProp({propName: 'colors', propValue: labelsArray}); + }, + getColors: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getColors for ' + this.__self._theChart.config.data.datasets[0].backgroundColor.join(',')); + return this.__self._theChart.config.data.datasets[0].backgroundColor; + }, + setDatasetLabel: function (theLabel) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setDatasetLabel to ' + theLabel); + this.__self._setProp({propName: 'datasetLabel', propValue: theLabel}); + }, + getDatasetLabel: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getDatasetLabel for ' + this.__self._theChart.config.data.datasets[0].label); + return this.__self._theChart.config.data.datasets[0].label; + }, + setDebugFlag: function(debugFlag) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setDebugFlag to ' + debugFlag); + this.__self._setProp({propName: 'debugFlag', propValue: debugFlag}); + }, + getDebugFlag: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getDebugFlag for ' + this.__self._debugFlag); + return this.__self._debugFlag; + } + } + return facade; + } + }; + widgetInstance._init(context, domNode, initialProps, eventManager); + return widgetInstance; + } +}; +nitro.registerWidget(leapSample.donutWidget); \ No newline at end of file diff --git a/samples/chart-widget/webpack.config.js b/samples/chart-widget/webpack.config.js new file mode 100644 index 0000000..a76089a --- /dev/null +++ b/samples/chart-widget/webpack.config.js @@ -0,0 +1,21 @@ +const path = require('path'); +const CopyPlugin = require("copy-webpack-plugin"); + +module.exports = (env) => { + return { + mode: 'development', + watch: !!env.watch, + entry: './src/chartJS.js', + output: { + filename: 'chartJS.js', + path: path.resolve(__dirname, 'dist') + }, + plugins: [ + new CopyPlugin({ + patterns: [ + { from: "src" }, + ], + }), + ], + }; +} diff --git a/samples/colorPicker-widget/README.md b/samples/colorPicker-widget/README.md new file mode 100644 index 0000000..6ba2b95 --- /dev/null +++ b/samples/colorPicker-widget/README.md @@ -0,0 +1,98 @@ +# Color Picker Widget + +A sample widget that uses the [HTML Color Picker element](https://www.w3schools.com/colors/colors_picker.asphttps:/) for the currently used browser. +The widget is completely programmable + +![](assets/20240422_142705_image.png) + +Above picture shows the rendering on the Chrome Browser on MacOS. + +The widget is a **Data Widget**, and the value that it manages is the string representation of the color. This string is fully managed by the HTML widget and it is stored in **HCL Leap / HCL Domino **Leap as its hexadecimal representation. + +When the widget is instantiated at runtime, it gets a unique HTML ID following this convention: `'coloPicker' + Date.now()`. + +## Widget Properties and events + +![](assets/20240422_143646_image.png) + +### Properties + +--- + +* **Enable Debug** + When set, verbose output is generated on the browser console + + ![](assets/20240422_143845_image.png) +* **Width** + The *width* of the widget can be modified on respect to its default values. The *width* can be expressed as "**px**" or as "**percentage**". Please be sure to use the following format: + + * `px` when using "pixels" (for instance 100px or 50px...) + * `%`when using "percentage" (for instance 100% or 20%). The percentage is on respect to the grid cell containing the color-picker: thus `100%` means that the widget takes all the width of the grid cell. +* **Height** + The *height* of the widget can be modified on respect to its default values. The *height* can **only** be expressed as "**px**" using the format`px`(for instance 100px or 50px...) +* **OnHover Description** + A string that appears when the user passes the mouse "over" the widget + +### Events + +--- + +The widget honors the **onChange event**. In this way, the form Author can assign some custom behavior when the form User selects a different color. + +### Programming the Color Picker Widget + +--- + +The following APIs allow the Author to programmatically perform the following operations: + +- `getDisplayTitle() / setTitle(string)` + Gets and sets the **title** of the widget +- `getValue() / setValue(string)` + Gets the **value** of the widget and Sets its value. + - When setting the value of the color, the value itself can be expressed as RGB, HEXadecimal or "Text" string as explained [here](#summary-of-the-color-properties) + - When getting the value of the color using the `getValue() `function, it always returns an HEXadecimal string. +- `getValueRGB()` + Gets the **RGB** representation of the Widget's value in the form `rgb(int, int, int)` +- `getValueText()` + Gets the **Text** representation of the Widget's value (for instance 'red', or 'black', or 'cyan' or 'lightblue'...) +- `convertToHex(string)` + Converts an **RGB** or **Text** representation of a color to its **HEXadecimal** counterpart. +- `getWidth() / setWidth(string)` + Gets and sets the **width** of the Color-Picker **widget**. For the widget's **width**, please be sure to use the following format: + - `px` when using "pixels" (for instance 100px or 50px...) + - `%` when using "percentage" (for instance 100% or 20%). The percentage is on respect to the grid cell containing the color-picker: thus `100%` means that the widget takes all the width of the grid cell. +- `getHeight() / setHeight(string)` + Gets and sets the **width** of the Color-Picker **height**. For the widget's **height**, please be sure to use the format`px`(for instance 100px or 50px...) +- `getDebugFlag() / setDebugFlag(boolean)` + Gets and sets the *Debug flag* for the widget instance + +### Summary of the color properties + +--- + +Each color can be expressed as RGB, HEXadecimal or "Text" according to the following syntax: + +* ***RGB***: rgb(int, int, int) +* ***HEX***: #HHHHHH +* ***Text***: "*lightblue*", "*red*", "*cyan*" ... or any valid textual value + * Not all colors have a **Text** representation + +## Run + +Take the `colorPicker.js`and `colorPicker.css` files and place them onto a web server. + +- **HCL Leap** configuration + Add the following to `Leap_config.properties`: +```properties +ibm.nitro.NitroConfig.runtimeResources.1 = \ + \n\ + +``` + +- **HCL domino Leap** configuration + *HCL Domino Leap* configuration is done similarly by adding a config setting in `VoltConfig.nsf` : + + + ![](assets/20240422_175838_image.png) + +## Credits diff --git a/samples/colorPicker-widget/assets/20240422_142705_image.png b/samples/colorPicker-widget/assets/20240422_142705_image.png new file mode 100644 index 0000000..c32babb Binary files /dev/null and b/samples/colorPicker-widget/assets/20240422_142705_image.png differ diff --git a/samples/colorPicker-widget/assets/20240422_143620_image.png b/samples/colorPicker-widget/assets/20240422_143620_image.png new file mode 100644 index 0000000..27ff9f4 Binary files /dev/null and b/samples/colorPicker-widget/assets/20240422_143620_image.png differ diff --git a/samples/colorPicker-widget/assets/20240422_143646_image.png b/samples/colorPicker-widget/assets/20240422_143646_image.png new file mode 100644 index 0000000..e8a4d88 Binary files /dev/null and b/samples/colorPicker-widget/assets/20240422_143646_image.png differ diff --git a/samples/colorPicker-widget/assets/20240422_143845_image.png b/samples/colorPicker-widget/assets/20240422_143845_image.png new file mode 100644 index 0000000..2c8b295 Binary files /dev/null and b/samples/colorPicker-widget/assets/20240422_143845_image.png differ diff --git a/samples/colorPicker-widget/assets/20240422_175838_image.png b/samples/colorPicker-widget/assets/20240422_175838_image.png new file mode 100644 index 0000000..c2b8487 Binary files /dev/null and b/samples/colorPicker-widget/assets/20240422_175838_image.png differ diff --git a/samples/colorPicker-widget/colorPicker.css b/samples/colorPicker-widget/colorPicker.css new file mode 100644 index 0000000..3b6cf19 --- /dev/null +++ b/samples/colorPicker-widget/colorPicker.css @@ -0,0 +1,8 @@ +/* + Code for ColorPicker widget + =========================== +*/ +.flex-wrapper { + display: flex; + flex-flow: row nowrap; + } diff --git a/samples/colorPicker-widget/colorPicker.js b/samples/colorPicker-widget/colorPicker.js new file mode 100644 index 0000000..379b0e1 --- /dev/null +++ b/samples/colorPicker-widget/colorPicker.js @@ -0,0 +1,589 @@ +if (typeof leapSample === 'undefined') { + leapSample = {}; // use an isolated namespace +}; + + +leapSample.colorPickerWidget = { + id: "leapSample.leap.sample.colorPicker", + version: "1.0.0", + apiVersion: "1.0.0", + label: { + "default": "Color Picker Widget", + "it": "Esempio Color Picker", + }, + description: { + "default": "Provides a way to select a color", + "it": "Il nuovo Color Picker", + "fr": "Le nouveau widget pour faire le Color Picker" + }, + datatype: { + type: 'string', + defautValue: '#000000' + }, + category: { + id: "hcl.leap.sample.widgets", + label: { + "default": "ColorPicker", + "it": "ColorPicker", + } + }, + formPalette: true, + appPagePalette: true, + iconClassName: "checkmarkIcon", + builtInProperties: [{ + id: "title" + }, + { + id: "id", + }, + { + id: "required", + }, + { + id: "seenInOverview", + defaultValue: true + } + ], + properties: [ + { + id: "debugFlag", + propType: "boolean", + label: { + "default": "Enable Debug", + "it": "Abilita debug" + }, + defaultValue: { + "default": false + } + }, + { + id: "theWidth", + propType: "string", + label: { + "default": "Width (px or %)", + "it": "Larghezza (px o %)" + }, + defaultValue: "" + }, + { + id: "theHeight", + propType: "string", + label: { + "default": "Height (pw)", + "it": "Altezza (px)" + }, + defaultValue: "" + }, + { + id: "explanationText", + propType: "string", + label: { + "default": "OnHover Description", + "it": "Descrizione OnHover" + }, + defaultValue: "OnHover Text" + } + ], + + // initialize widget in the DOM, with initial properties and event callbacks + instantiate: function (context, domNode, initialProps, eventManager) { + const rgbRegex = /([R][G][B][A]?[(]\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\s*,\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\s*,\s*([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])(\s*,\s*((0\.[0-9]{1})|(1\.0)|(1)))?[)])/i + const hexRegex = /^[#]*([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/i + let widgetInstance = { + _mode: null, + _valueNode: null, + _flexNode: null, + _fieldsetNode: null, + _legendNode: null, + _debugFlag: true, + _theId: context.id, + /** + * IMPORTANT: Avoids script injection + */ + _sanitizeHTML: function (str) { + let s = '' + str; + s = s.replace(/&/g, '&').replace(//g, '>').replace(/'/g, ''').replace(/"/g, '"'); + return s; + }, + _debugMsg: function(ctx, msg) { + if (ctx._debugFlag) console.log(ctx._theId + msg); + }, + // + // Hexadecimal, RGB, Saturation, Literals + // + // Check Functions + _checkHex: function (hex) { + return hexRegex.test(hex); + }, + + _checkRgb: function (rgb) { + return rgbRegex.test(rgb); + }, + + // Parse Function + _modifyHex: function (hex) { + let newHex = hex; + if (newHex.length === 4) { + newHex = newHex.replace('#', ''); + } + if (newHex.length === 3) { + newHex = newHex[0] + newHex[0] + newHex[1] + newHex[1] + newHex[2] + newHex[2]; + } + this._debugMsg(this, '._modifyHex : converting ' + hex + ' to ' + newHex); + return newHex; + }, + + // Helper Functions + _addPound: function (x) { + return '#' + x; + }, + // + // Converting Functions + // + _hexToRgb: function (hex) { + let x = []; + if (! this._checkHex(hex)) { + this._debugMsg(this, '._hexToRgB: ' + hex + ' is not valid. Returning DEFAULT'); + return 'rgb(0,0,0)'; + } + + let newHex = hex.replace('#', ''); + if (newHex.length !== 6) { + newHex = this._modifyHex(newHex); + } + x.push(parseInt(newHex.slice(0, 2), 16)); + x.push(parseInt(newHex.slice(2, 4), 16)); + x.push(parseInt(newHex.slice(4, 6), 16)); + let theResult = "rgb(" + x.toString() + ")" + this._debugMsg(this, '._hexToRgB: ' + hex + ' converted tp ' + theResult); + return theResult; + }, + _rgbToHex: function (rgb) { + let rgbArray = rgbRegex.exec(rgb); + if (rgbArray) { + let result = '#' + parseInt(rgbArray[2]).toString(16).padStart(2, '0') + + parseInt(rgbArray[3]).toString(16).padStart(2, '0') + + parseInt(rgbArray[4]).toString(16).padStart(2, '0'); + if (rgbArray[6]) { + // + // Intensity + // + result += Math.round(rgbArray[6] * 255).toString(16).padStart(2, '0'); + } + this._debugMsg(this, '._rgbToHex: i' + rgb + ' converted to ' + result.toUpperCase()); + return result.toUpperCase(); + } else { + this._debugMsg(this, '._rgbToHex: invalid rgb definition : ' + rgb + ' . returning DEFAULT'); + return '#000000'; + } + }, + _wordToHex : { + aliceblue: "#F0F8FF", + antiquewhite: "#FAEBD7", + aqua: "#00FFFF", + aquamarine: "#7FFFD4", + azure: "#F0FFFF", + beige: "#F5F5DC", + bisque: "#FFE4C4", + black: "#000000", + blanchedalmond: "#FFEBCD", + blue: "#0000FF", + blueviolet: "#8A2BE2", + brown: "#A52A2A", + burlywood: "#DEB887", + cadetblue: "#5F9EA0", + chartreuse: "#7FFF00", + chocolate: "#D2691E", + coral: "#FF7F50", + cornflowerblue: "#6495ED", + cornsilk: "#FFF8DC", + crimson: "#DC143C", + cyan: "#00FFFF", + darkblue: "#00008B", + darkcyan: "#008B8B", + darkgoldenrod: "#B8860B", + darkgray: "#A9A9A9", + darkgrey: "#A9A9A9", + darkgreen: "#006400", + darkkhaki: "#BDB76B", + darkmagenta: "#8B008B", + darkolivegreen: "#556B2F", + darkorange: "#FF8C00", + darkorchid: "#9932CC", + darkred: "#8B0000", + darksalmon: "#E9967A", + darkseagreen: "#8FBC8F", + darkslateblue: "#483D8B", + darkslategray: "#2F4F4F", + darkslategrey: "#2F4F4F", + darkturquoise: "#00CED1", + darkviolet: "#9400D3", + deeppink: "#FF1493", + deepskyblue: "#00BFFF", + dimgray: "#696969", + dimgrey: "#696969", + dodgerblue: "#1E90FF", + firebrick: "#B22222", + floralwhite: "#FFFAF0", + forestgreen: "#228B22", + fuchsia: "#FF00FF", + gainsboro: "#DCDCDC", + ghostwhite: "#F8F8FF", + gold: "#FFD700", + goldenrod: "#DAA520", + gray: "#808080", + grey: "#808080", + green: "#008000", + greenyellow: "#ADFF2F", + honeydew: "#F0FFF0", + hotpink: "#FF69B4", + indianred: "#CD5C5C", + indigo: "#4B0082", + ivory: "#FFFFF0", + khaki: "#F0E68C", + lavender: "#E6E6FA", + lavenderblush: "#FFF0F5", + lawngreen: "#7CFC00", + lemonchiffon: "#FFFACD", + lightblue: "#ADD8E6", + lightcoral: "#F08080", + lightcyan: "#E0FFFF", + lightgoldenrodyellow: "#FAFAD2", + lightgray: "#D3D3D3", + lightgrey: "#D3D3D3", + lightgreen: "#90EE90", + lightpink: "#FFB6C1", + lightsalmon: "#FFA07A", + lightseagreen: "#20B2AA", + lightskyblue: "#87CEFA", + lightslategray: "#778899", + lightslategrey: "#778899", + lightsteelblue: "#B0C4DE", + lightyellow: "#FFFFE0", + lime: "#00FF00", + limegreen: "#32CD32", + linen: "#FAF0E6", + magenta: "#FF00FF", + maroon: "#800000", + mediumaquamarine: "#66CDAA", + mediumblue: "#0000CD", + mediumorchid: "#BA55D3", + mediumpurple: "#9370DB", + mediumseagreen: "#3CB371", + mediumslateblue: "#7B68EE", + mediumspringgreen: "#00FA9A", + mediumturquoise: "#48D1CC", + mediumvioletred: "#C71585", + midnightblue: "#191970", + mintcream: "#F5FFFA", + mistyrose: "#FFE4E1", + moccasin: "#FFE4B5", + navajowhite: "#FFDEAD", + navy: "#000080", + oldlace: "#FDF5E6", + olive: "#808000", + olivedrab: "#6B8E23", + orange: "#FFA500", + orangered: "#FF4500", + orchid: "#DA70D6", + palegoldenrod: "#EEE8AA", + palegreen: "#98FB98", + paleturquoise: "#AFEEEE", + palevioletred: "#DB7093", + papayawhip: "#FFEFD5", + peachpuff: "#FFDAB9", + peru: "#CD853F", + pink: "#FFC0CB", + plum: "#DDA0DD", + powderblue: "#B0E0E6", + purple: "#800080", + rebeccapurple: "#663399", + red: "#FF0000", + rosybrown: "#BC8F8F", + royalblue: "#4169E1", + saddlebrown: "#8B4513", + salmon: "#FA8072", + sandybrown: "#F4A460", + seagreen: "#2E8B57", + seashell: "#FFF5EE", + sienna: "#A0522D", + silver: "#C0C0C0", + skyblue: "#87CEEB", + slateblue: "#6A5ACD", + slategray: "#708090", + slategrey: "#708090", + snow: "#FFFAFA", + springgreen: "#00FF7F", + steelblue: "#4682B4", + tan: "#D2B48C", + teal: "#008080", + thistle: "#D8BFD8", + tomato: "#FF6347", + turquoise: "#40E0D0", + violet: "#EE82EE", + wheat: "#F5DEB3", + white: "#FFFFFF", + whitesmoke: "#F5F5F5", + yellow: "#FFFF00", + yellowgreen: "#9ACD32" + }, + _hexToWord: function() { + let inverse = Object.entries(this._wordToHex).map(([k, v]) => [v, k]); + let out = Object.fromEntries(inverse); + return out; + }, + _toHex: function(color) { + this._debugMsg(this, '._toHex: checking HEX for color : ' + color); + let result = this._wordToHex[color.toLowerCase()]; + if (result) { + this._debugMsg(this, '._toHex: returning HEX : ' + result); + return result; + } else { + this._debugMsg(this, '._toHex: No correspondance. Returning undefined'); + return 'UNDEFINED'; + } + }, + _fromHex: function(hex) { + this._debugMsg(this, '._fromHex: checking Color for HEX : ' + hex); + let theArray = this._hexToWord(); + let result = theArray[hex.toUpperCase()]; + if (result) { + this._debugMsg(this, '._fromHex: returning Color : ' + result); + return result; + } else { + this._debugMsg(this, '._fromHex: No correspondance. Returning undefined'); + return 'UNDEFINED'; + } + }, + // + // internal method for creating and initializing the widget + // + _init: function (context, domNode, initialProps, eventManager) { + if (initialProps.debugFlag && (initialProps.debugFlag === true)) console.log(JSON.stringify(initialProps, ' ', 4)); + this._mode = context.mode; + const isDisabled = this._mode === 'design'; + const groupName = this._sanitizeHTML(context.id); + + const widgetHTML = '' + + '
\n' + + ' \n' + + '
\n' + + ' \n' + + '
\n' + + '
'; + + domNode.innerHTML = widgetHTML; + this._fieldsetNode = domNode.firstChild; + this._legendNode = this._fieldsetNode.querySelector('legend'); + this._flexNode = this._fieldsetNode.querySelector('.flex-wrapper'); + this._valueNode = this._flexNode.querySelector('input'); + // set initial prop values + Object.keys(initialProps).forEach((propName) => { + this._setProp({propName: propName, propValue: initialProps[propName]}); + }); + + // propagate events + this._valueNode.addEventListener("input", () => { + // will trigger call to getValue() + this._debugMsg(this, '.changeListener: CHANGE EVENT'); + eventManager.sendEvent('onChange'); + }); + /* + this._fieldsetNode.addEventListener("click", () => { + //this._debugMsg(this, '.clickListener: CLICK EVENT'); + //eventManager.sendEvent('onClick'); + }); + this._fieldsetNode.addEventListener("focus", () => { + //this._debugMsg(this, '.focusListener: FOCUS EVENT'); + //eventManager.sendEvent('onFocus'); + }); + this._fieldsetNode.addEventListener("blur", () => { + //this._debugMsg(this, '.blurListener: BLUR EVENT'); + //eventManager.sendEvent('onBlur'); + }); + this._fieldsetNode.addEventListener("focus", () => { + //this._debugMsg(this, '.focusListener: FOCUS EVENT'); + //eventManager.sendEvent('onFocus'); + }); + this._valueNode.addEventListener("mouseover", () => { + //this._debugMsg(this, '.mouseOverListener: MOUSEOVER EVENT'); + //alert('INPUT ' + this._valueNode.value); + //eventManager.sendEvent('onMouseOver'); + }); + this._fieldsetNode.addEventListener("mouseout", () => { + //this._debugMsg(this, '.mouseOutListener: MOUSEOUT EVENT'); + //eventManager.sendEvent('onMouseOut'); + }); + */ + }, + // internal custom mechanics for changing widget props + _setProp: function ({propName, propValue}) { + this._debugMsg(this, '._setProp: Setting ' + propName + ' to ' + propValue); + switch (propName) { + case "title": + this._legendNode.innerHTML = this._sanitizeHTML(propValue); + break; + case "explanationText": + this._fieldsetNode.setAttribute('title', propValue); + break; + case "theWidth": + this._valueNode.style["width"] = this._sanitizeHTML(propValue); + break; + case "theHeight": + this._valueNode.style["height"] = this._sanitizeHTML(propValue); + break; + case "debugFlag": + this._debugFlag = propValue; + break; + default: + // ignore + break; + } + }, + // + // for display in various parts of the UI + // + getDisplayTitle: function () { + this._debugMsg(this, '.getDisplayTitle : ' + this._legendNode.innerHTML); + return this._legendNode.innerHTML; + }, + // + // must be supplied for Leap to get widget's data value + // + getValue: function () { + this._debugMsg(this, '.getValue : ' + this._valueNode.value); + return this._valueNode.value; + }, + // + // must be supplied for Leap to set widget's data value + // + setValue: function (val) { + this._debugMsg(this, '.setValue : ' + val); + // + // checking if value is HEXA + // + if (this._checkHex(val)) { + // + // Hexadecimal + // + this._valueNode.value = val.replaceAll(' ', ''); + } else { + // + // Problem + // + this._debugMsg(this, '.setValue : Value not an HEXADecimal. Setting to DEFAULT'); + this._valueNode.value = "#000000"; + } + }, + // + // called when properties change in the authoring environment, or via JavaScript API + // + setProperty: function (propName, propValue) { + this._debugMsg(this, '.setProperty ' + propName + ' to ' + propValue); + this._setProp({propName, propValue}); + }, + // + // determines what the author can do with the widget via custom JavaScript + // + getJSAPIFacade: function () { + this._debugMsg(this, '.getJSAPIFacade: defining FACADE'); + const facade = { + __self: this, // double-underscore keeps this private + setTitle: function (theTitle) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setTitle : ' + theTitle); + this.__self._setProp({propName: 'title', propValue: theTitle}); + }, + getValueRGB: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getValueRGB for ' + this.__self.getValue()); + return this.__self._hexToRgb(this.__self.getValue()); + }, + getValueText: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getValueText for ' + this.__self.getValue()); + return this.__self._fromHex(this.__self.getValue()); + }, + setWidth: function(theWidth) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setWidth to ' + theWidth); + this.__self._setProp({propName: 'theWidth', propValue: theWidth}); + }, + getWidth: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getWidth to ' + this.__self._valueNode.style["width"]); + return this.__self._valueNode.style["width"]; + }, + setHeight: function(theHeight) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setHeight to ' + theHeight); + this.__self._setProp({propName: 'theHeight', propValue: theHeight}); + }, + getHeight: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getHeight to ' + this.__self._valueNode.style["height"]); + return this.__self._valueNode.style["height"]; + }, + setDebugFlag: function(debugFlag) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setDebugFlag to ' + debugFlag); + this.__self._setProp({propName: 'debugFlag', propValue: debugFlag}); + }, + getDebugFlag: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getDebugFlag for ' + this.__self._debugFlag); + return this.__self._debugFlag; + }, + convertToHex: function(val) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: convertToHex : ' + val); + let theResult = null; + // + // checking if value is HEXA + // + if (this.__self._checkHex(val)) { + // + // Hexadecimal + // + theResult = val.replaceAll(' ', ''); + } else { + // + // Check if RGB + // + if (this.__self._checkRgb(val)) { + // + // RGBA value + // + theResult = this.__self._rgbToHex(val); + } else { + // + // Check if HSL + // + if (false) { + // + // HSLA + // + } else { + // + // literal + // + theResult = this.__self._toHex(val); + } + } + } + this.__self._debugMsg(this.__self, '.getJSAPIFacade: convertToHex to result ' + theResult); + return theResult; + } + } + return facade; + }, + // + // Magaing Disabling the Widget + // + setDisabled: function (isDisabled) { + // always disable in the authoring environment + this._debugMsg(this, '.setDisabled : ' + isDisabled); + const disabled = context.mode === 'design' || isDisabled; + this._fieldsetNode.classList.toggle('disabled', disabled); + this._valueNode.disabled = true; + } + }; + widgetInstance._init(context, domNode, initialProps, eventManager); + if (context.mode === 'design') { + //widgetInstance.setDisabled(true); + } + + return widgetInstance; + } +}; +nitro.registerWidget(leapSample.colorPickerWidget); \ No newline at end of file diff --git a/samples/colorPicker-widget/index.html b/samples/colorPicker-widget/index.html new file mode 100644 index 0000000..ad61850 --- /dev/null +++ b/samples/colorPicker-widget/index.html @@ -0,0 +1,9 @@ + + + + My Website + + +

Hello World

+ + diff --git a/samples/gauge-widget/README.md b/samples/gauge-widget/README.md new file mode 100644 index 0000000..fd4725b --- /dev/null +++ b/samples/gauge-widget/README.md @@ -0,0 +1,123 @@ +# Gauge Widget + +A sample widget that displays an SVG-based, completely programmable "Gauge" widget. + +![](assets/gauge_1.png) + +The widget is a **Display Widget**, so it does not hold data by itself but can be used to display data coming from other widgets. +When the widget is instantiated at runtime, it gets a unique HTML ID following this convention: `gauge_' + Date.now()`. + +## Widget Properties and events + +![](assets/20240416_172042_image.png) + +### Properties + +--- + +* **Enable Debug** + When set, verbose output is generated on the browser console + + ![](assets/20240416_172904_image.png) +* **Gauge Value** + Even if this is a "*Display Widget*", this property allows to initialize the value shown in the Gauge. + Positive integer only. +* **Label** + This is the text that is displayed at the middle of the widget. +* **Gauge Scale** + The "*Gauge Value*" needs to be relative to a "scale". + For instance, a "*Gauge Value*" of 25 on a "*Gauge Scale*" of 100 will display a quarter of a circle strikeout. + Positive integer only. +* **Stroke color** + The color of the "stroke", the part of the widget showing the visualization of the value. See the section ["Summary of the color properties"](#summary-of-the-color-properties) below. +* **Gap color** + The color of the "gap", the part of the widget that completes the "*stroke*". See the section ["Summary of the color properties"](#summary-of-the-color-properties) below. +* **Widget Text Color** + This is the color used to display the "*Label*" and the "*Gauge Value*". See the section ["Summary of the color properties"](#summary-of-the-color-properties) below. +* **Selected Widget Fill color** + When the widget is clicked, the background color changes to visually represent the fact that the widget has been selected. See the section ["Summary of the color properties"](#summary-of-the-color-properties) below. +* **Is Clickable** + When this property is set, the user can click the widget (and this will trigger a change in the background color). + In addition to the background color change, the "**click**" event is triggered which can be captured by the widget's **onClick** event handler (where the form Author can add custom code). + If this property is not set, the widget will not deliver the "onClick" event nor the background color of the widget will change. +* **OnHover Description** + A string that appears when the user passes the mouse "over" the widget + +### Events + +--- + +The widget honors the **click event**. In this way, the form Author can assign some custom behavior when the form User clicks on the widget. +The default behavior is that the widget changes the "fill color" (see the section ["Summary of the color properties"](#summary-of-the-color-properties) below). Clicking twice resets the "fill color" to the default one. + +The click event can be statically and/or dynamically blocked by means of: +* the **Is Clickable** property available during the editing of the widget +* the `selectWidget()` API + +### Programming the Gauge Widget + +--- + +The following APIs allow the Author to programmatically perform the following operations: + +* `getTitle() / setTitle(string)` + Gets and sets the title of the widget +* `getValue() / setValue(positive integer)` + Gets the value currently shown by the widget and Sets the value shown by the widget +* `getLabel() / setLabel(string)` + Gets and sets the value of the Label shown inside the circle of the Gauge widget +* `getScale() / setScale(positive integer)` + Gets and sets the scale of the Gauge in order to correctly represent the value +* `getTextColor() / setTextColor(string)` + Gets and sets the color of the "*value*" and of the "*label*" of the widget +* `getStrokeColor() / setStrokeColor(string)` + Gets and sets the color of the "*stroke*" of the widget +* `getGapColor() / setGapColor(string)` + Gets and sets the color of the "*gap*" of the widget +* `getFillColor() / setFillColor(string)` + Gets and sets the color of the "*background*" of the Gauge when it is selected +* `getClickable() / setClickable(boolean)` + Gets and sets the *clickable-state* of the widget +* `selectWidget() / unselectWidget()` + Programmatically selects or unselects the widget. It has the same behavior has clicking on the widget. + These operaions do not yield any result in case the widget is in a *non-clickable state*. +* `isWidgetSelected()` + Returns **true** in case the widget is selected or **false** in case the widget is not selected +* `toggleSelection()` + It toggles the selection of the widget **on** or **off** +* `getDebugFlag() / setDebugFlag(boolean)` + Gets and sets the *Debug flag* for the widget instance + +### Summary of the color properties + +--- + +Each color can be expressed as RGB, HEXadecimal or "Text" according to the following syntax: +* ***RGB***: rgb(int, int, int) +* ***HEX***: #HHHHHH +* ***Text***: "*lightblue*", "*red*", "*cyan*" ... or any valid textual value + * Not all colors have a **Text** representation + +Here a **short summary of the colors attributes** used by the Widget: +![](assets/20240416_174609_image.png) + +## Run + +Take the `gauge.js`and `gauge.css` files and place them onto a web server. + +- **HCL Leap** configuration + Add the following to `Leap_config.properties`: +```properties +ibm.nitro.NitroConfig.runtimeResources.1 = \ + \n\ + +``` + +- **HCL domino Leap** configuration + *HCL Domino Leap* configuration is done similarly by adding a config setting in `VoltConfig.nsf`. + +![](assets/20240422_175239_image.png) + +## Credits + +This widget has been inspired by the original code available [here](https://codepen.io/tnhu/pen/BayGGqR). diff --git a/samples/gauge-widget/assets/20240416_172042_image.png b/samples/gauge-widget/assets/20240416_172042_image.png new file mode 100644 index 0000000..37f7a8c Binary files /dev/null and b/samples/gauge-widget/assets/20240416_172042_image.png differ diff --git a/samples/gauge-widget/assets/20240416_172904_image.png b/samples/gauge-widget/assets/20240416_172904_image.png new file mode 100644 index 0000000..e93f2a4 Binary files /dev/null and b/samples/gauge-widget/assets/20240416_172904_image.png differ diff --git a/samples/gauge-widget/assets/20240416_174609_image.png b/samples/gauge-widget/assets/20240416_174609_image.png new file mode 100644 index 0000000..0d1266f Binary files /dev/null and b/samples/gauge-widget/assets/20240416_174609_image.png differ diff --git a/samples/gauge-widget/assets/20240422_175239_image.png b/samples/gauge-widget/assets/20240422_175239_image.png new file mode 100644 index 0000000..8bc153c Binary files /dev/null and b/samples/gauge-widget/assets/20240422_175239_image.png differ diff --git a/samples/gauge-widget/assets/gauge_1.png b/samples/gauge-widget/assets/gauge_1.png new file mode 100644 index 0000000..a2f9a84 Binary files /dev/null and b/samples/gauge-widget/assets/gauge_1.png differ diff --git a/samples/gauge-widget/gauge copy.css b/samples/gauge-widget/gauge copy.css new file mode 100644 index 0000000..4f266e7 --- /dev/null +++ b/samples/gauge-widget/gauge copy.css @@ -0,0 +1,46 @@ +/* + Code for GAUGES and SVG + ======================= +*/ +.flex-wrapper { + display: flex; + flex-flow: row nowrap; + } + + .single-chart { + width: 100%; + justify-content: space-around ; + } + + .circular-chart { + display: block; + margin: 10px auto; + max-width: 80%; + max-height: 250px; + } + + .circle-bg { + fill: none; + stroke: #eee; + stroke-width: 3.8; + } + + .circle { + fill: none; + stroke-width: 2.8; + stroke-linecap: round; + animation: progress 1s ease-out forwards; + } + + .percentage { + fill: #666; + font-family: sans-serif; + font-size: 0.5em; + text-anchor: middle; + } + + @keyframes progress { + 0% { + stroke-dasharray: 0 100; + } + } diff --git a/samples/gauge-widget/gauge copy.js b/samples/gauge-widget/gauge copy.js new file mode 100644 index 0000000..753f336 --- /dev/null +++ b/samples/gauge-widget/gauge copy.js @@ -0,0 +1,388 @@ +if (typeof acme1 === 'undefined') { + acme1 = {}; // use an isolated namespace +}; + +acme1.makeHTMLSafe = function (str) { + if (!str) return str; + var s = str.replace(/&/g, '&'); + s = s.replace(//g, '>'); + s = s.replace(/'/g, '''); + s = s.replace(/"/g, '"'); + return s; +}; + + +acme1.gaugeWidget = { + id: "acme1.theGauge", + version: "1.0.0", + apiVersion: "1.0.0", + label: { + "default": "ACME Gauge Widget", + "it": "ACME Widget Gauge", + }, + description: { + "default": "ACME The new Gauge widget", + "it": "Il nuovo Gauge widget di ACME", + "fr": "Le nouveau widget de type Gauge de ACME" + }, + datatype: { + type: 'number', + numberType: 'decimal', + defautValue: 25, + minValue: 0 + }, + category: { + id: "acme1-gauge-widgets", + label: { + "default": "Gauges", + "it": "Gauges", + } + }, + formPalette: true, + appPagePalette: true, + iconClassName: "checkmarkIcon", + builtInProperties: [{ + id: "title" + }, + { + id: "id", + }, + { + id: "required", + }, + { + id: "seenInOverview", + defaultValue: true + } + ], + properties: [ + { + id: "explanationText", + propType: "string", + label: { + "default": "Explanation Text", + "nl": "Uitleg tekst" + }, + defaultValue: { + "default": "Some default explanation text", + "nl": "Een standaard uitlegtekst" + } + }, + { + id: "poster", + propType: "string", + label: { + "default": "Poster", + "it": "Etichetta" + }, + defaultValue: { + "default": "This Sample", + "it": "questo esempio" + } + }, + { + id: "scale", + propType: "number", + label: { + "default": "Gauge Scale", + "it": "La Scale del Gauge" + }, + defaultValue: 100, + constraints: { + "minValue": 0 + } + }, + { + id: "strokeColor", + propType: "string", + label: { + "default": "Stroke Color", + "it": "Colore gauge" + }, + defaultValue: { + "default": "red" + } + }, + { + id: "widgeTextColor", + propType: "string", + label: { + "default": "Widget Text Color", + "it": "Colore testo gauge" + }, + defaultValue: { + "default": "#666" + } + }, + { + id: "widgetFillColor", + propType: "string", + label: { + "default": "Selected Widget Fill Color", + "it": "Colore Background selezione" + }, + defaultValue: { + "default": "lightblue" + } + } + ], + + // initialize widget in the DOM, with initial properties and event callbacks + instantiate: function (context, domNode, initialProps, eventManager) { + let widgetInstance = { + _mode: null, + _thePoster: null, + _theScale: 100, + _widgetFillColor: null, + _valueNode: null, + _posterNode: null, + _strokeNode: null, + _flexNode: null, + _radioGroupNode: null, + _legendNode: null, + + // internal custom mechanics for changing widget props + _setProp: function ({ + propName, + propValue + }) { + console.log('theGauge._setProp: Setting ' + propName + ' to ' + propValue); + switch (propName) { + case "title": + this._legendNode.innerHTML = acme1.makeHTMLSafe(propValue); + break; + case "explanationText": + this._radioGroupNode.setAttribute('title', propValue); + break; + case "scale": + this._theScale = propValue; + let perc = (this._valueNode.innerHTML * 120) / this._theScale; + if (this._mode !== 'design') this._strokeNode.style['stroke-dasharray'] = perc + ', 120'; + break; + case "poster": + this._posterNode.innerHTML = acme1.makeHTMLSafe(propValue); + break; + case "strokeColor": + this._strokeNode.style['stroke'] = acme1.makeHTMLSafe(propValue); + break; + case "widgetTextColor": + this._posterNode.style['fill'] = acme1.makeHTMLSafe(propValue); + this._valueNode.style['fill'] = acme1.makeHTMLSafe(propValue); + break; + case "widgetFillColor": + this._widgetFillColor = acme1.makeHTMLSafe(propValue); + // if (this._mode !== 'design') this._strokeNode.style['fill'] = this._widgetFillColor; + break; + default: + // ignore + break; + } + }, + + // internal method for creating and initializing the widget + _init: function (context, domNode, initialProps, eventManager) { + this._mode = context.mode; + //const isDisabled = this._mode === 'design'; + const isDisabled = false; + const groupName = acme1.makeHTMLSafe(context.id); + + const widgetHTML = '' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' ' + 'UNDEF' + '\n' + + ' ' + 25 + '\n' + + ' \n' + + '
\n' + + '
\n' + + '
'; + + domNode.innerHTML = widgetHTML; + this._radioGroupNode = domNode.firstChild; + this._legendNode = this._radioGroupNode.querySelector('legend'); + this._flexNode = this._radioGroupNode.querySelector('.flex-wrapper'); + this._posterNode = this._radioGroupNode.querySelector('.first-line'); + this._valueNode = this._radioGroupNode.querySelector('.second-line'); + this._strokeNode = this._radioGroupNode.querySelector('.circle'); + // set initial prop values + Object.keys(initialProps).forEach((propName) => { + this._setProp({ + propName: propName, + propValue: initialProps[propName] + }); + }); + + // propagate events + this._radioGroupNode.addEventListener("change", () => { + // will trigger call to getValue() + console.log('theGauge.changeListener: CHANGE EVENT'); + eventManager.sendEvent('onChange'); + }); + this._radioGroupNode.addEventListener("click", () => { + console.log('theGauge.clickListener: CLICK EVENT'); + if (this._mode !== 'design') { + if (this._strokeNode.style['fill'] === '') { + this._strokeNode.style['fill'] = this._widgetFillColor; + } else { + this._strokeNode.style['fill'] = ''; + } + } + eventManager.sendEvent('onClick'); + }); + this._radioGroupNode.addEventListener("focus", () => { + //console.log('theGauge.focusListener: FOCUS EVENT'); + eventManager.sendEvent('onFocus'); + }); + this._radioGroupNode.addEventListener("blur", () => { + //console.log('theGauge.blurListener: BLUR EVENT'); + eventManager.sendEvent('onBlur'); + }); + this._radioGroupNode.addEventListener("focus", () => { + //console.log('theGauge.focusListener: FOCUS EVENT'); + eventManager.sendEvent('onFocus'); + }); + this._radioGroupNode.addEventListener("mouseover", () => { + //console.log('theGauge.mouseOverListener: MOUSEOVER EVENT'); + eventManager.sendEvent('onMouseOver'); + }); + this._radioGroupNode.addEventListener("mouseout", () => { + //console.log('theGauge.mouseOutListener: MOUSEOUT EVENT'); + eventManager.sendEvent('onMouseOut'); + }); + }, + + // for display in various parts of the UI + getDisplayTitle: function () { + console.log('theGauge.getDisplayTitle : ' + this._legendNode.innerHTML); + return this._legendNode.innerHTML; + }, + + // must be supplied for Leap to get widget's data value + getValue: function () { + console.log('theGauge.getValue: '); + return this._valueNode.innerHTML; + }, + + // must be supplied for Leap to set widget's data value + setValue: function (val) { + console.log('theGauge.setValue: ' + val); + this._valueNode.innerHTML = val; + let perc = (val * 120) / this._theScale; + this._strokeNode.style['stroke-dasharray'] = perc + ', 120'; + }, + + // called when properties change in the authoring environment, or via JavaScript API + setProperty: function (propName, propValue) { + this._setProp({ + propName, + propValue + }); + }, + + setDisabled: function (isDisabled) { + // TODO - to be implemented + }, + + getOptions: function () { + return null; + }, + + // determines what the author can do with the widget via custom JavaScript + getJSAPIFacade: function () { + console.log('theGauge.getJSAPIFacade: defining FACADE'); + const facade = { + __self: this, // double-underscore keeps this private + setTitle: function (theTitle) { + console.log('theGauge.getJSAPIFacade: setTitle : ' + theTitle); + this.__self._setProp({ + propName: 'title', + propValue: theTitle + }); + }, + setPoster: function (label) { + console.log('theGauge.getJSAPIFacade: setPoster : ' + label); + this.__self._setProp({ + propName: 'poster', + propValue: label + }); + }, + setScale: function (scale) { + console.log('theGauge.getJSAPIFacade: setScale : ' + scale); + this.__self._setProp({ + propName: 'scale', + propValue: scale + }); + }, + setTextColor: function (theColor) { + console.log('theGauge.getJSAPIFacade: setTextColor : ' + theColor); + this.__self._setProp({ + propName: 'widgetTextColor', + propValue: theColor + }); + }, + setStrokeColor: function (theColor) { + console.log('theGauge.getJSAPIFacade: setStrokeColor : ' + theColor); + this.__self._setProp({ + propName: 'strokeColor', + propValue: theColor + }); + }, + setFillColor: function (theColor) { + console.log('theGauge.getJSAPIFacade: setFillColor : ' + theColor); + this.__self._setProp({ + propName: 'widgetFillColor', + propValue: theColor + }); + }, + selectWidget: function () { + if (this.__self._strokeNode.style['fill'] === '') { + console.log('theGauge.getJSAPIFacade: selectWidget'); + this.__self._strokeNode.style['fill'] = this.__self._widgetFillColor; + } else { + console.log('theGauge.getJSAPIFacade: selectWidget : ALREADY SELECTED'); + } + }, + unselectWidget: function () { + if (this.__self._strokeNode.style['fill'] === '') { + console.log('theGauge.getJSAPIFacade: unselectWidget : ALREADY UNSELECTED'); + } else { + console.log('theGauge.getJSAPIFacade: unselectWidget'); + this.__self._strokeNode.style['fill'] = ''; + } + }, + toggleSelection : function () { + console.log('theGauge.getJSAPIFacade: toggleSelection '); + if (this.__self._strokeNode.style['fill'] === '') { + this.__self._strokeNode.style['fill'] = this.__self._widgetFillColor; + } else { + this.__self._strokeNode.style['fill'] = ''; + } + }, + isWidgetSelected: function () { + console.log('theGauge.getJSAPIFacade: isWidgetSelected'); + if (this.__self._strokeNode.style['fill'] === '') { + return false; + } else { + return true; + } + } + } + return facade; + } + }; + widgetInstance._init(context, domNode, initialProps, eventManager); + return widgetInstance; + } +}; +nitro.registerWidget(acme1.gaugeWidget); \ No newline at end of file diff --git a/samples/gauge-widget/gauge.css b/samples/gauge-widget/gauge.css new file mode 100644 index 0000000..9d9acde --- /dev/null +++ b/samples/gauge-widget/gauge.css @@ -0,0 +1,46 @@ +/* + Code for GAUGES and SVG + ======================= +*/ +.flex-wrapper { + display: flex; + flex-flow: row nowrap; + } + + .single-chart { + width: 100%; + justify-content: space-around ; + } + + .circular-chart { + display: block; + margin: 10px auto; + max-width: 80%; + max-height: 100%; + } + + .circle-bg { + fill: none; + stroke: #eee; + stroke-width: 3.8; + } + + .circle { + fill: none; + stroke-width: 2.8; + stroke-linecap: round; + animation: progress 1s ease-out forwards; + } + + .percentage { + fill: #666; + font-family: sans-serif; + font-size: 0.5em; + text-anchor: middle; + } + + @keyframes progress { + 0% { + stroke-dasharray: 0 100; + } + } diff --git a/samples/gauge-widget/gauge.js b/samples/gauge-widget/gauge.js new file mode 100644 index 0000000..282d66f --- /dev/null +++ b/samples/gauge-widget/gauge.js @@ -0,0 +1,497 @@ +if (typeof leapSample === 'undefined') { + leapSample = {}; // use an isolated namespace +} + + +leapSample.gaugeWidget = { + id: "leapSample.leap.sample.Gauge", + version: "1.0.0", + apiVersion: "1.0.0", + label: { + "default": "Gauge Widget", + "it": "Gauge widget", + }, + description: { + "default": "Displays a Gauge to display data", + "it": "Il nuovo Gauge widget", + "fr": "Le nouveau widget de type Gauge" + }, + category: { + id: "hcl.leap.sample.widgets", + label: { + "default": "Leap Samples", + "it": "Esempi per Leap", + } + }, + formPalette: true, + appPagePalette: true, + iconClassName: "checkmarkIcon", + builtInProperties: [{ + id: "title" + }, + { + id: "id", + }, + { + id: "required", + }, + { + id: "seenInOverview", + defaultValue: true + } + ], + properties: [ + { + id: "debugFlag", + propType: "boolean", + label: { + "default": "Enable Debug", + "it": "Abilita debug" + }, + defaultValue: true + }, + { + id: "theData", + propType: "number", + label: { + "default": "Gauge Value", + "it": "Il Valore del Gauge" + }, + defaultValue: 25, + constraints: { + "minValue": 0, + "numberType": "integer" + } + }, + { + id: "scale", + propType: "number", + label: { + "default": "Gauge Scale", + "it": "La Scale del Gauge" + }, + defaultValue: 100, + constraints: { + "minValue": 0, + "numberType": "integer" + } + }, + { + id: "poster", + propType: "string", + label: { + "default": "Label", + "it": "Etichetta" + }, + defaultValue: "Sample" + }, + { + id: "strokeColor", + propType: "string", + label: { + "default": "Stroke Color", + "it": "Colore gauge" + }, + defaultValue: "red" + }, + { + id: "gapColor", + propType: "string", + label: { + "default": "Gap Color", + "it": "Colore gap" + }, + defaultValue: "rgb(238,238,238)" + }, + { + id: "widgetTextColor", + propType: "string", + label: { + "default": "Widget Text Color", + "it": "Colore testo gauge" + }, + defaultValue: "#666" + }, + { + id: "isClickable", + propType: "boolean", + label: { + "default": "Is Clickable", + "it": "é cliccabile" + }, + defaultValue: true + }, + { + id: "widgetFillColor", + propType: "string", + label: { + "default": "Selected Widget Fill Color", + "it": "Colore Background selezione" + }, + defaultValue: "lightblue" + }, + { + id: "explanationText", + propType: "string", + label: { + "default": "OnHover Description", + "it": "Descrizione OnHover" + }, + defaultValue: "OnHover Text" + } + ], + + // initialize widget in the DOM, with initial properties and event callbacks + instantiate: function (context, domNode, initialProps, eventManager) { + let widgetInstance = { + _mode: null, + _thePoster: null, + _theScale: 100, + _widgetFillColor: null, + _valueNode: null, + _posterNode: null, + _strokeNode: null, + _gapNode: null, + _flexNode: null, + _fieldsetNode: null, + _legendNode: null, + _debugFlag: true, + _isClickable: true, + _theId: context.id, + /** + * IMPORTANT: Avoids script injection + */ + _sanitizeHTML: function (str) { + let s = '' + str; + s = s.replace(/&/g, '&').replace(//g, '>').replace(/'/g, ''').replace(/"/g, '"'); + return s; + }, + _debugMsg: function(ctx, msg) { + if (ctx._debugFlag) console.log(ctx._theId + msg); + }, + // + // internal method for creating and initializing the widget + // + _init: function (context, domNode, initialProps, eventManager) { + if (initialProps.debugFlag && (initialProps.debugFlag === true)) console.log(JSON.stringify(initialProps, ' ', 4)); + this._mode = context.mode; + const groupName = this._sanitizeHTML(context.id); + + const widgetHTML = '' + + '
\n' + + ' \n' + + '
\n' + + '
\n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' ' + 'UNDEF' + '\n' + + ' ' + 25 + '\n' + + ' \n' + + '
\n' + + '
\n' + + '
'; + + domNode.innerHTML = widgetHTML; + this._fieldsetNode = domNode.firstChild; + this._legendNode = this._fieldsetNode.querySelector('legend'); + this._flexNode = this._fieldsetNode.querySelector('.flex-wrapper'); + this._posterNode = this._fieldsetNode.querySelector('.first-line'); + this._valueNode = this._fieldsetNode.querySelector('.second-line'); + this._strokeNode = this._fieldsetNode.querySelector('.circle'); + this._gapNode = this._fieldsetNode.querySelector('.circle-bg'); + // set initial prop values + Object.keys(initialProps).forEach((propName) => { + this._setProp({propName: propName, propValue: initialProps[propName]}); + }); + + // propagate events + this._fieldsetNode.addEventListener("click", () => { + if (this._isClickable) { + this._debugMsg(this, '.clickListener: Honoring CLICK EVENT'); + if (this._mode !== 'design') this.getJSAPIFacade().toggleSelection(); + eventManager.sendEvent('onClick'); + } else { + this._debugMsg(this, '.clickListener: IGNORING CLICK EVENT as this widget is in a NOT-CLICKABLE state'); + } + }); + /* + this._fieldsetNode.addEventListener("change", () => { + // will trigger call to getValue() + this._debugMsg(this, '.changeListener: CHANGE EVENT'); + eventManager.sendEvent('onChange'); + }); + this._fieldsetNode.addEventListener("focus", () => { + //if (this._debugFlag) console.log(this._theId + '.focusListener: FOCUS EVENT'); + //eventManager.sendEvent('onFocus'); + }); + this._fieldsetNode.addEventListener("blur", () => { + //if (this._debugFlag) console.log(this._theId + '.blurListener: BLUR EVENT'); + //eventManager.sendEvent('onBlur'); + }); + this._fieldsetNode.addEventListener("focus", () => { + //if (this._debugFlag) console.log(this._theId + '.focusListener: FOCUS EVENT'); + //eventManager.sendEvent('onFocus'); + }); + this._fieldsetNode.addEventListener("mouseover", () => { + //if (this._debugFlag) console.log(this._theId + '.mouseOverListener: MOUSEOVER EVENT'); + //eventManager.sendEvent('onMouseOver'); + }); + this._fieldsetNode.addEventListener("mouseout", () => { + //if (this._debugFlag) console.log(this._theId + '.mouseOutListener: MOUSEOUT EVENT'); + //eventManager.sendEvent('onMouseOut'); + }); + */ + }, + _setProp: function ({propName, propValue}) { + this._debugMsg(this, '._setProp: Setting ' + propName + ' to ' + propValue); + switch (propName) { + case "theData": + this._valueNode.innerHTML = propValue; + let perc1 = (propValue * 120) / this._theScale; + this._strokeNode.style['stroke-dasharray'] = perc1 + ', 120'; + break; + case "title": + this._legendNode.innerHTML = this._sanitizeHTML(propValue); + break; + case "explanationText": + this._fieldsetNode.setAttribute('title', propValue); + break; + case "scale": + this._theScale = propValue; + let perc = (this._valueNode.innerHTML * 120) / this._theScale; + this._strokeNode.style['stroke-dasharray'] = perc + ', 120'; + //if (this._mode !== 'design') this._strokeNode.style['stroke-dasharray'] = perc + ', 120'; + break; + case "poster": + this._posterNode.innerHTML = this._sanitizeHTML(propValue); + break; + case "strokeColor": + this._strokeNode.style['stroke'] = this._sanitizeHTML(propValue); + break; + case "gapColor": + this._gapNode.style['stroke'] = this._sanitizeHTML(propValue); + break; + case "widgetTextColor": + this._posterNode.style['fill'] = this._sanitizeHTML(propValue); + this._valueNode.style['fill'] = this._sanitizeHTML(propValue); + break; + case "widgetFillColor": + this._widgetFillColor = this._sanitizeHTML(propValue); + if (this._gapNode.style['fill'] !== '') this._gapNode.style['fill'] = this._widgetFillColor; + //this._strokeNode.style['fill'] = this._widgetFillColor; + //if (this._mode !== 'design') this._strokeNode.style['fill'] = this._widgetFillColor; + break; + case "debugFlag": + this._debugFlag = propValue; + break; + case "isClickable": + this._isClickable = propValue; + break; + default: + // ignore + break; + } + }, + // internal custom mechanics for getting widget props + _getProp: function (propName) { + this._debugMsg(this, '._getProp: Getting ' + propName + '...'); + switch (propName) { + case "theData": + return this._valueNode.innerHTML; + break; + case "title": + return this._legendNode.innerHTML;; + break; + case "explanationText": + return this._fieldsetNode.getAttribute('title'); + break; + case "scale": + return this._theScale; + break; + case "poster": + return this._posterNode.innerHTML; + break; + case "strokeColor": + return this._strokeNode.style['stroke']; + break; + case "gapColor": + return this._gapNode.style['stroke']; + break; + case "widgetTextColor": + return this._valueNode.style['fill']; + break; + case "widgetFillColor": + return this._widgetFillColor; + break; + case "debugFlag": + return this._debugFlag; + case "isClickable": + return this._isClickable; + default: + return null; + // ignore + break; + } + }, + // + // for display in various parts of the UI + // + getDisplayTitle: function () { + this._debugMsg(this, '.getDisplayTitle : ' + this._getProp('title')); + return this._getProp('title'); + }, + // + // called when properties change in the authoring environment, or via JavaScript API + // + setProperty: function (propName, propValue) { + this._debugMsg(this, '.setProperty ' + propName + ' to ' + propValue); + this._setProp({propName, propValue}); + }, + // + // determines what the author can do with the widget via custom JavaScript + // + getJSAPIFacade: function () { + this._debugMsg(this, '.getJSAPIFacade: defining FACADE'); + const facade = { + __self: this, // double-underscore keeps this private + setTitle: function (theTitle) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setTitle : ' + theTitle); + this.__self._setProp({propName: 'title', propValue: theTitle}); + }, + getTitle: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getTitle for ' + this.__self._getProp('title')); + return this.__self._getProp('title'); + }, + setValue: function (theData) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setValue : ' + theData); + this.__self._setProp({propName: 'theData', propValue: theData}); + }, + getValue: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getValue for ' + this.__self._valueNode.innerHTML); + return this.__self._valueNode.innerHTML; + }, + setLabel: function (label) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setLabel : ' + label); + this.__self._setProp({propName: 'poster', propValue: label}); + }, + getLabel: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getLabel for ' + this.__self._getProp('poster')); + return this.__self._getProp('poster'); + }, + setScale: function (scale) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setScale : ' + scale); + this.__self._setProp({propName: 'scale', propValue: scale}); + }, + getScale: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getScale for ' + this.__self._getProp('scale')); + return this.__self._getProp('scale'); + }, + setTextColor: function (theColor) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setTextColor : ' + theColor); + this.__self._setProp({propName: 'widgetTextColor', propValue: theColor}); + }, + getTextColor: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getTextColor for ' + this.__self._getProp('widgetTextColor')); + return this.__self._getProp('widgetTextColor'); + }, + setStrokeColor: function (theColor) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setStrokeColor : ' + theColor); + this.__self._setProp({propName: 'strokeColor', propValue: theColor}); + }, + getStrokeColor: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getStrokeColor for ' + this.__self._getProp('strokeColor')); + return this.__self._getProp('strokeColor'); + }, + setGapColor: function (theColor) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setGapColor : ' + theColor); + this.__self._setProp({propName: 'gapColor', propValue: theColor}); + }, + getGapColor: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getGapColor for ' + this.__self._getProp('gapColor')); + return this.__self._getProp('gapColor'); + }, + setFillColor: function (theColor) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setFillColor : ' + theColor); + this.__self._setProp({propName: 'widgetFillColor', propValue: theColor}); + }, + getFillColor: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getFillColor for ' + this.__self._getProp('widgetFillColor')); + return this.__self._getProp('widgetFillColor'); + }, + setClickable: function(isClickable) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setClickable to ' + isClickable); + this.__self._setProp({propName: 'isClickable', propValue: isClickable}); + }, + getClickable: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getClickable for ' + this.__self._getProp('isClickable')); + return this.__self._getProp('isClickable'); + }, + selectWidget: function () { + if (this.__self._isClickable) { + if (this.__self._gapNode.style['fill'] === '') { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: selectWidget : selecting Widget...'); + this.__self._gapNode.style['fill'] = this.__self._widgetFillColor; + } else { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: selectWidget : Widget ALREADY selected'); + } + } else { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: selectWidget : widget is NOT CLICKABLE! This operation is ignored !'); + } + }, + unselectWidget: function () { + if (this.__self._isClickable) { + if (this.__self._gapNode.style['fill'] === '') { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: unselectWidget : Widget ALREADY unselected'); + } else { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: unselectWidget : unselecting Widget...'); + this.__self._gapNode.style['fill'] = ''; + } + } else { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: unselectWidget : widget is NOT CLICKABLE! This operation is ignored !'); + } + }, + toggleSelection : function () { + if (this.__self._isClickable) { + if (this.__self._gapNode.style['fill'] === '') { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: toggleSelection ON'); + this.__self._gapNode.style['fill'] = this.__self._widgetFillColor; + } else { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: toggleSelection OFF'); + this.__self._gapNode.style['fill'] = ''; + } + } else { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: toggleSelection : widget is NOT CLICKABLE! This operation is ignored !'); + } + }, + isWidgetSelected: function () { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: isWidgetSelected...'); + if (this.__self._gapNode.style['fill'] === '') { + return false; + } else { + return true; + } + }, + setDebugFlag: function(debugFlag) { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: setDebugFlag to ' + debugFlag); + this.__self._setProp({propName: 'debugFlag', propValue: debugFlag}); + }, + getDebugFlag: function() { + this.__self._debugMsg(this.__self, '.getJSAPIFacade: getDebugFlag for ' + this.__self._debugFlag); + return this.__self._debugFlag; + } + } + return facade; + } + }; + widgetInstance._init(context, domNode, initialProps, eventManager); + return widgetInstance; + } +}; +nitro.registerWidget(leapSample.gaugeWidget); diff --git a/samples/gauge-widget/index.html b/samples/gauge-widget/index.html new file mode 100644 index 0000000..ad61850 --- /dev/null +++ b/samples/gauge-widget/index.html @@ -0,0 +1,9 @@ + + + + My Website + + +

Hello World

+ + diff --git a/samples/package.json b/samples/package.json new file mode 100644 index 0000000..db40f4c --- /dev/null +++ b/samples/package.json @@ -0,0 +1,29 @@ +{ + "name": "hcl-leap-custom-widgets-react-mui", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.10.6", + "@emotion/styled": "^11.10.6", + "@mui/material": "^5.12.0", + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@vitejs/plugin-react": "^4.0.3", + "eslint": "^8.45.0", + "eslint-plugin-react": "^7.32.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "vite": "^4.4.5" + } +}