zynaui 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +491 -0
- package/dist/base-CaP9Us8w.js +89 -0
- package/dist/base-DyLOr2iL.cjs +1 -0
- package/dist/charts/lollipop.cjs +1 -0
- package/dist/charts/lollipop.js +38 -0
- package/dist/charts/nightingale.cjs +1 -0
- package/dist/charts/nightingale.js +35 -0
- package/dist/charts/orbital.cjs +1 -0
- package/dist/charts/orbital.js +48 -0
- package/dist/charts/timeline.cjs +1 -0
- package/dist/charts/timeline.js +32 -0
- package/dist/charts/waffle.cjs +1 -0
- package/dist/charts/waffle.js +27 -0
- package/dist/genres.cjs +1 -0
- package/dist/genres.js +7 -0
- package/dist/index-6PLXN0mK.js +313 -0
- package/dist/index-CznVizeu.cjs +1 -0
- package/dist/react.cjs +1 -0
- package/dist/react.js +67 -0
- package/dist/zyna-charts-stub.cjs +5 -0
- package/dist/zyna-charts.cjs +1 -0
- package/dist/zyna-charts.iife.js +1 -0
- package/dist/zyna-charts.js +12 -0
- package/dist/zyna-plugin.cjs +1 -0
- package/dist/zyna-plugin.js +949 -0
- package/dist/zynaui.css +1836 -0
- package/package.json +137 -0
- package/src/charts/base.js +159 -0
- package/src/charts/index.js +6 -0
- package/src/charts/lollipop.js +132 -0
- package/src/charts/nightingale.js +118 -0
- package/src/charts/orbital.js +176 -0
- package/src/charts/timeline.js +128 -0
- package/src/charts/waffle.js +75 -0
- package/src/index.js +6 -0
- package/src/plugin/components/alert/alert.js +222 -0
- package/src/plugin/components/badge/badge.js +254 -0
- package/src/plugin/components/btn/btn.js +289 -0
- package/src/plugin/components/card/card.js +308 -0
- package/src/plugin/components/index.js +14 -0
- package/src/plugin/genres/cyberpunk.js +163 -0
- package/src/plugin/genres/define.js +59 -0
- package/src/plugin/genres/index.js +49 -0
- package/src/plugin/genres/ops.js +144 -0
- package/src/plugin/index.js +81 -0
- package/src/plugin/tokens.js +105 -0
- package/src/plugin/utils/motion.js +30 -0
- package/src/plugin/utils/prefix.js +54 -0
- package/src/plugin/utils/shapes.js +48 -0
- package/src/react/index.js +84 -0
- package/types/charts.d.ts +121 -0
- package/types/genres.d.ts +98 -0
- package/types/index.d.ts +65 -0
- package/types/react.d.ts +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Binary Tech Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
# Zyna UI
|
|
2
|
+
|
|
3
|
+
> Tailwind CSS component library + D3-powered chart Web Components
|
|
4
|
+
> Built by [Binary Tech Ltd](https://binary.ly) · Open source · MIT License
|
|
5
|
+
|
|
6
|
+
[](https://www.npmjs.com/package/zynaui)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://zyna.dev)
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What's included
|
|
13
|
+
|
|
14
|
+
| Package | Description |
|
|
15
|
+
|---------|-------------|
|
|
16
|
+
| **Tailwind plugin** | Semantic classes: `.btn`, `.card`, `.badge`, `.alert` |
|
|
17
|
+
| **Chart Web Components** | `<zyna-waffle>`, `<zyna-timeline>`, `<zyna-nightingale>`, `<zyna-lollipop>`, `<zyna-orbital>` |
|
|
18
|
+
|
|
19
|
+
Framework-agnostic — works in React, Vue, Svelte, Blade, or plain HTML.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## UI Components (Tailwind Plugin)
|
|
24
|
+
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install zynaui tailwindcss
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Tailwind v3** — `tailwind.config.js`:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
module.exports = {
|
|
35
|
+
content: ['./src/**/*.{html,js,jsx,ts,tsx,vue,svelte}'],
|
|
36
|
+
plugins: [require('zynaui')],
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Tailwind v4** — `app.css`:
|
|
41
|
+
|
|
42
|
+
```css
|
|
43
|
+
@import "tailwindcss";
|
|
44
|
+
@plugin "zynaui";
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### Plugin options
|
|
50
|
+
|
|
51
|
+
#### `prefix` — avoid class name conflicts
|
|
52
|
+
|
|
53
|
+
If another library in your project already uses `.btn`, `.card`, `.badge`, or `.alert`, add a prefix:
|
|
54
|
+
|
|
55
|
+
**Tailwind v3:**
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
plugins: [require('zynaui')({ prefix: 'z-' })]
|
|
59
|
+
// → .z-btn, .z-btn-primary, .z-card, .z-badge, .z-alert …
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Tailwind v4:**
|
|
63
|
+
|
|
64
|
+
```css
|
|
65
|
+
@plugin "zynaui" {
|
|
66
|
+
prefix: z-;
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### Tailwind utilities
|
|
73
|
+
|
|
74
|
+
ZynaUI extends the Tailwind theme with semantic color and radius tokens, so you can use them as native utility classes:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<!-- Status colors -->
|
|
78
|
+
<span class="text-zyna-success">Operational</span>
|
|
79
|
+
<span class="text-zyna-danger">Critical</span>
|
|
80
|
+
<span class="text-zyna-warning">Degraded</span>
|
|
81
|
+
<span class="text-zyna-info">Updating</span>
|
|
82
|
+
<span class="text-zyna-muted">Offline</span>
|
|
83
|
+
|
|
84
|
+
<!-- Brand color -->
|
|
85
|
+
<span class="text-zyna">Gold accent</span>
|
|
86
|
+
|
|
87
|
+
<!-- Corner radius (respects active genre) -->
|
|
88
|
+
<div class="rounded-zyna-sm">…</div>
|
|
89
|
+
<div class="rounded-zyna">…</div>
|
|
90
|
+
<div class="rounded-zyna-lg">…</div>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
These resolve to CSS variables (e.g. `text-zyna-success` → `color: var(--z-color-success)`) and update automatically when the active genre changes.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### Buttons
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<button class="btn btn-primary">Primary</button>
|
|
101
|
+
<button class="btn btn-secondary">Secondary</button>
|
|
102
|
+
<button class="btn btn-ghost">Ghost</button>
|
|
103
|
+
<button class="btn btn-danger">Danger</button>
|
|
104
|
+
|
|
105
|
+
<!-- Sizes -->
|
|
106
|
+
<button class="btn btn-primary btn-sm">Small</button>
|
|
107
|
+
<button class="btn btn-primary btn-lg">Large</button>
|
|
108
|
+
|
|
109
|
+
<!-- Icon button -->
|
|
110
|
+
<button class="btn btn-primary btn-icon">
|
|
111
|
+
<svg>…</svg>
|
|
112
|
+
</button>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Custom button variant** — set CSS variables, no plugin changes needed:
|
|
116
|
+
|
|
117
|
+
```css
|
|
118
|
+
.btn-plasma {
|
|
119
|
+
--btn-bg: rgba(139, 0, 255, 0.38);
|
|
120
|
+
--btn-color: #BF5FFF;
|
|
121
|
+
--btn-filter: drop-shadow(0 0 8px rgba(139,0,255,0.45));
|
|
122
|
+
--btn-scan-color: rgba(139, 0, 255, 0.18);
|
|
123
|
+
--btn-hover-filter: drop-shadow(0 0 22px rgba(139,0,255,1)) brightness(1.10);
|
|
124
|
+
--btn-hover-text-shadow: 0 0 16px rgba(200,100,255,0.7);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### Badges
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<span class="badge badge-primary">New</span>
|
|
134
|
+
<span class="badge badge-success badge-pulse">Active</span>
|
|
135
|
+
<span class="badge badge-danger">Error</span>
|
|
136
|
+
<span class="badge badge-warning">Pending</span>
|
|
137
|
+
<span class="badge badge-info">Info</span>
|
|
138
|
+
<span class="badge badge-neutral">Draft</span>
|
|
139
|
+
|
|
140
|
+
<!-- Large -->
|
|
141
|
+
<span class="badge badge-primary badge-lg">Featured</span>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Custom badge variant:**
|
|
145
|
+
|
|
146
|
+
```css
|
|
147
|
+
.badge-plasma {
|
|
148
|
+
--badge-bg: rgba(139, 0, 255, 0.10);
|
|
149
|
+
--badge-color: #BF5FFF;
|
|
150
|
+
--badge-glow: drop-shadow(0 0 5px rgba(139,0,255,0.45))
|
|
151
|
+
drop-shadow(0 0 14px rgba(139,0,255,0.14));
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Cards
|
|
158
|
+
|
|
159
|
+
```html
|
|
160
|
+
<div class="card">
|
|
161
|
+
<div class="card-header">System Status</div>
|
|
162
|
+
<div class="card-body">
|
|
163
|
+
<p class="card-title">Card Title</p>
|
|
164
|
+
<p class="card-subtitle">Supporting subtitle</p>
|
|
165
|
+
<p>Body content here.</p>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="card-footer">Footer</div>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<!-- Variants -->
|
|
171
|
+
<div class="card card-dark">…</div>
|
|
172
|
+
<div class="card card-glow">…</div>
|
|
173
|
+
<div class="card card-compact">…</div>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Custom card variant:**
|
|
177
|
+
|
|
178
|
+
```css
|
|
179
|
+
.card-cyber {
|
|
180
|
+
--card-gradient: linear-gradient(145deg, rgba(0,20,30,0.97) 0%, rgba(0,10,18,0.97) 100%);
|
|
181
|
+
--card-border-color: rgba(0,212,255,0.22);
|
|
182
|
+
--card-bracket-color: rgba(0,212,255,0.55);
|
|
183
|
+
--card-bar-gradient: linear-gradient(90deg, transparent 0%, rgba(0,212,255,0.55) 25%, rgba(0,212,255,0.55) 75%, transparent 100%);
|
|
184
|
+
--card-glow-lo: rgba(0,212,255,0.12);
|
|
185
|
+
--card-glow-hi: rgba(0,212,255,0.26);
|
|
186
|
+
--card-animation: zyna-card-pulse 4s ease-in-out infinite;
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### Alerts
|
|
193
|
+
|
|
194
|
+
```html
|
|
195
|
+
<div class="alert alert-success">
|
|
196
|
+
<p class="alert-title">Success</p>
|
|
197
|
+
<p>Your changes have been saved.</p>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<div class="alert alert-danger">…</div>
|
|
201
|
+
<div class="alert alert-warning">…</div>
|
|
202
|
+
<div class="alert alert-info">…</div>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Custom alert variant:**
|
|
206
|
+
|
|
207
|
+
```css
|
|
208
|
+
.alert-plasma {
|
|
209
|
+
--alert-bar-color: #BF5FFF;
|
|
210
|
+
--alert-bg: rgba(139, 0, 255, 0.055);
|
|
211
|
+
--alert-color: rgba(191, 95, 255, 0.88);
|
|
212
|
+
--alert-shadow: 0 0 30px rgba(139,0,255,0.08),
|
|
213
|
+
inset 4px 0 18px rgba(139,0,255,0.05);
|
|
214
|
+
--alert-title-shadow: 0 0 12px rgba(191,95,255,0.65);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Chart Web Components
|
|
221
|
+
|
|
222
|
+
### React & Next.js — typed wrapper components
|
|
223
|
+
|
|
224
|
+
Install the wrapper and get typed React components that accept native arrays and numbers:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
npm install zynaui
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```tsx
|
|
231
|
+
import { ZynaWaffle, ZynaTimeline, ZynaNightingale, ZynaLollipop, ZynaOrbital } from 'zynaui/react'
|
|
232
|
+
|
|
233
|
+
export default function Charts() {
|
|
234
|
+
const data = [
|
|
235
|
+
{ label: 'Food', value: 35, color: '#C9A84C' },
|
|
236
|
+
{ label: 'Shelter', value: 25, color: '#009EDB', outline: true },
|
|
237
|
+
]
|
|
238
|
+
return <ZynaWaffle data={data} cols={10} gap={3} />
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The `'use client'` directive is baked into the package — works with Next.js App Router out of the box. The IIFE bundle is inlined, so no file copying or `next/script` setup is needed.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### Via bundler (Vue / Svelte / Astro)
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
import 'zynaui/charts'
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Individual chart imports
|
|
253
|
+
|
|
254
|
+
```js
|
|
255
|
+
import 'zynaui/charts/waffle'
|
|
256
|
+
import 'zynaui/charts/timeline'
|
|
257
|
+
import 'zynaui/charts/nightingale'
|
|
258
|
+
import 'zynaui/charts/lollipop'
|
|
259
|
+
import 'zynaui/charts/orbital'
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Via CDN / Vanilla HTML (no bundler)
|
|
263
|
+
|
|
264
|
+
Link the pre-compiled CSS and load the IIFE bundle — no build step needed:
|
|
265
|
+
|
|
266
|
+
```html
|
|
267
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/zynaui/dist/zynaui.css" />
|
|
268
|
+
<script src="https://cdn.jsdelivr.net/npm/zynaui/dist/zyna-charts.iife.js"></script>
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Or if installed via npm:
|
|
272
|
+
|
|
273
|
+
```html
|
|
274
|
+
<link rel="stylesheet" href="node_modules/zynaui/dist/zynaui.css" />
|
|
275
|
+
<script src="node_modules/zynaui/dist/zyna-charts.iife.js"></script>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
### `<zyna-waffle>`
|
|
281
|
+
|
|
282
|
+
Waffle chart — square-grid cells, each filled or outline-only.
|
|
283
|
+
|
|
284
|
+
| Attribute | Type | Default | Description |
|
|
285
|
+
|-----------|------|---------|-------------|
|
|
286
|
+
| `data` | JSON array | `[]` | `[{ label, value, color?, outline? }]` |
|
|
287
|
+
| `color` | hex | `#C9A84C` | Fallback cell color |
|
|
288
|
+
| `cols` | number | `10` | Grid columns |
|
|
289
|
+
| `gap` | number | `3` | Gap between cells (px) |
|
|
290
|
+
|
|
291
|
+
```html
|
|
292
|
+
<zyna-waffle
|
|
293
|
+
data='[
|
|
294
|
+
{ "label": "UK", "value": 24, "color": "#1A3A6B" },
|
|
295
|
+
{ "label": "US", "value": 28, "color": "#009EDB" },
|
|
296
|
+
{ "label": "EU", "value": 20, "color": "#4A6741", "outline": true }
|
|
297
|
+
]'
|
|
298
|
+
></zyna-waffle>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
### `<zyna-timeline>`
|
|
304
|
+
|
|
305
|
+
Proportional-circle timeline — bubble area encodes value.
|
|
306
|
+
|
|
307
|
+
| Attribute | Type | Default | Description |
|
|
308
|
+
|-----------|------|---------|-------------|
|
|
309
|
+
| `data` | JSON array | `[]` | `[{ label, value, note? }]` |
|
|
310
|
+
| `color` | hex | `#C9A84C` | Accent color for highlighted item |
|
|
311
|
+
| `theme` | `dark`/`light` | `dark` | Color theme |
|
|
312
|
+
| `highlight` | string | highest value | Label of the item to emphasize |
|
|
313
|
+
|
|
314
|
+
```html
|
|
315
|
+
<zyna-timeline
|
|
316
|
+
data='[
|
|
317
|
+
{ "label": "2019", "value": 120 },
|
|
318
|
+
{ "label": "2020", "value": 95, "note": "COVID" },
|
|
319
|
+
{ "label": "2021", "value": 180 },
|
|
320
|
+
{ "label": "2022", "value": 210 }
|
|
321
|
+
]'
|
|
322
|
+
highlight="2022"
|
|
323
|
+
></zyna-timeline>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### `<zyna-nightingale>`
|
|
329
|
+
|
|
330
|
+
Nightingale (rose) chart — sector radius encodes value.
|
|
331
|
+
|
|
332
|
+
| Attribute | Type | Default | Description |
|
|
333
|
+
|-----------|------|---------|-------------|
|
|
334
|
+
| `data` | JSON array | `[]` | `[{ label, value, color? }]` |
|
|
335
|
+
| `color` | hex | `#C9A84C` | Fallback sector color |
|
|
336
|
+
| `theme` | `dark`/`light` | `dark` | Color theme |
|
|
337
|
+
|
|
338
|
+
```html
|
|
339
|
+
<zyna-nightingale
|
|
340
|
+
data='[
|
|
341
|
+
{ "label": "Food", "value": 42, "color": "#C9A84C" },
|
|
342
|
+
{ "label": "Shelter", "value": 31, "color": "#009EDB" },
|
|
343
|
+
{ "label": "Education", "value": 18, "color": "#00FFB2" },
|
|
344
|
+
{ "label": "Health", "value": 27, "color": "#FF3366" }
|
|
345
|
+
]'
|
|
346
|
+
></zyna-nightingale>
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
### `<zyna-lollipop>`
|
|
352
|
+
|
|
353
|
+
Horizontal lollipop chart — line + circle encodes value.
|
|
354
|
+
|
|
355
|
+
| Attribute | Type | Default | Description |
|
|
356
|
+
|-----------|------|---------|-------------|
|
|
357
|
+
| `data` | JSON array | `[]` | `[{ label, value }]` sorted descending recommended |
|
|
358
|
+
| `color` | hex | `#C9A84C` | Accent color for the top item |
|
|
359
|
+
| `theme` | `dark`/`light` | `dark` | Color theme |
|
|
360
|
+
|
|
361
|
+
```html
|
|
362
|
+
<zyna-lollipop
|
|
363
|
+
data='[
|
|
364
|
+
{ "label": "Libya", "value": 820 },
|
|
365
|
+
{ "label": "Sudan", "value": 610 },
|
|
366
|
+
{ "label": "Syria", "value": 490 },
|
|
367
|
+
{ "label": "Yemen", "value": 380 }
|
|
368
|
+
]'
|
|
369
|
+
></zyna-lollipop>
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
### `<zyna-orbital>`
|
|
375
|
+
|
|
376
|
+
Concentric arc chart — each ring filled as a proportion of a full circle.
|
|
377
|
+
|
|
378
|
+
| Attribute | Type | Default | Description |
|
|
379
|
+
|-----------|------|---------|-------------|
|
|
380
|
+
| `data` | JSON array | `[]` | `[{ label, value, color? }]` — `value` is `0`–`1` |
|
|
381
|
+
| `color` | hex | `#C9A84C` | Fallback ring color |
|
|
382
|
+
| `theme` | `dark`/`light` | `dark` | Color theme |
|
|
383
|
+
|
|
384
|
+
```html
|
|
385
|
+
<zyna-orbital
|
|
386
|
+
data='[
|
|
387
|
+
{ "label": "Delivered", "value": 0.78, "color": "#C9A84C" },
|
|
388
|
+
{ "label": "In Transit","value": 0.55, "color": "#009EDB" },
|
|
389
|
+
{ "label": "Planned", "value": 0.32, "color": "#00FFB2" }
|
|
390
|
+
]'
|
|
391
|
+
></zyna-orbital>
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Custom genres
|
|
397
|
+
|
|
398
|
+
Create a fully custom visual paradigm with `defineGenre`:
|
|
399
|
+
|
|
400
|
+
```js
|
|
401
|
+
import { defineGenre, registerGenre } from 'zynaui/genres'
|
|
402
|
+
|
|
403
|
+
const aurora = defineGenre({
|
|
404
|
+
name: 'Aurora',
|
|
405
|
+
palette: { brand: '#BF5FFF' },
|
|
406
|
+
tokens: {
|
|
407
|
+
'--zyna': '#BF5FFF',
|
|
408
|
+
'--z-ease-enter': 'cubic-bezier(0.34, 1.56, 0.64, 1)',
|
|
409
|
+
'--z-duration-fast': '0.14s',
|
|
410
|
+
},
|
|
411
|
+
styles: {
|
|
412
|
+
'html[data-genre="aurora"]': {
|
|
413
|
+
'--z-btn-clip': 'inset(0)',
|
|
414
|
+
'--z-badge-clip': 'inset(0 round 4px)',
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
registerGenre(aurora)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
Activate at runtime:
|
|
423
|
+
|
|
424
|
+
```js
|
|
425
|
+
document.documentElement.setAttribute('data-genre', 'aurora')
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
> **Note:** Genre structural styles (`styles`) are compiled into `zynaui.css` at Tailwind build time. Register custom genres before your build step runs so their rules are included in the output.
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
## Build
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
npm install
|
|
436
|
+
npm run build
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Outputs:
|
|
440
|
+
|
|
441
|
+
| File | Format | Use case |
|
|
442
|
+
|------|--------|----------|
|
|
443
|
+
| `dist/zyna-plugin.cjs` | CommonJS | Tailwind config `require()` |
|
|
444
|
+
| `dist/zyna-plugin.js` | ESM | Bundler import |
|
|
445
|
+
| `dist/genres.js` | ESM | `import { defineGenre } from 'zynaui/genres'` |
|
|
446
|
+
| `dist/zyna-charts.js` | ESM | Bundler `import 'zynaui/charts'` |
|
|
447
|
+
| `dist/zyna-charts.iife.js` | IIFE | `<script src>` with no bundler |
|
|
448
|
+
| `dist/zyna-charts-stub.cjs` | CJS stub | SSR environments (auto-selected) |
|
|
449
|
+
| `dist/react.js` | ESM | `import { ZynaWaffle } from 'zynaui/react'` |
|
|
450
|
+
| `dist/zynaui.css` | CSS | Pre-compiled CSS for CDN / vanilla HTML |
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
# Build only the Tailwind plugin
|
|
454
|
+
npm run build:lib
|
|
455
|
+
|
|
456
|
+
# Build only the IIFE bundle (CDN)
|
|
457
|
+
npm run build:iife
|
|
458
|
+
|
|
459
|
+
# Build only the docs CSS
|
|
460
|
+
npm run build:css
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## CSS Variable API
|
|
466
|
+
|
|
467
|
+
All components are driven entirely by CSS custom properties. Create custom variants without touching plugin source:
|
|
468
|
+
|
|
469
|
+
```css
|
|
470
|
+
/* A custom button — just set variables */
|
|
471
|
+
.btn-ocean {
|
|
472
|
+
--btn-bg: linear-gradient(135deg, #006994 0%, #003d5b 100%);
|
|
473
|
+
--btn-color: #7ED8F6;
|
|
474
|
+
--btn-filter: drop-shadow(0 0 8px rgba(0,105,148,0.5));
|
|
475
|
+
--btn-hover-filter: drop-shadow(0 0 22px rgba(0,185,255,0.9)) brightness(1.12);
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
See the JSDoc at the top of each component file in `src/plugin/components/` for the full variable reference.
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## Credits
|
|
484
|
+
|
|
485
|
+
The semantic component class naming convention (`.btn`, `.btn-primary`, `.card`, `.badge`, `.alert`, etc.) is inspired by [DaisyUI](https://daisyui.com) by Pouya Saadeghi — the leading semantic Tailwind component library. Zyna UI takes that convention and applies a dark, HUD-style aesthetic with CSS custom properties, clip-path geometry, and D3-powered chart Web Components.
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## License
|
|
490
|
+
|
|
491
|
+
MIT © [Binary Tech Ltd](https://binary.ly)
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
class l extends HTMLElement {
|
|
2
|
+
connectedCallback() {
|
|
3
|
+
this._lastW = 0, this._rafId = null, this._timerId = null, this._genreHandler = () => this._render(), window.addEventListener("zyna-genre", this._genreHandler), this._ro = new ResizeObserver((t) => {
|
|
4
|
+
var r;
|
|
5
|
+
const e = ((r = t[0]) == null ? void 0 : r.contentRect.width) ?? this.clientWidth;
|
|
6
|
+
if (Math.abs(e - this._lastW) < 3) return;
|
|
7
|
+
const i = this._lastW === 0;
|
|
8
|
+
this._lastW = e, this._rafId && cancelAnimationFrame(this._rafId), this._rafId = requestAnimationFrame(() => {
|
|
9
|
+
this._rafId = null, clearTimeout(this._timerId), i ? this._render() : this._timerId = setTimeout(() => this._render(), 150);
|
|
10
|
+
});
|
|
11
|
+
}), this._ro.observe(this), requestAnimationFrame(() => {
|
|
12
|
+
this._lastW === 0 && (this._lastW = this.clientWidth, this._render());
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
disconnectedCallback() {
|
|
16
|
+
var t;
|
|
17
|
+
(t = this._ro) == null || t.disconnect(), this._rafId && cancelAnimationFrame(this._rafId), this._timerId && clearTimeout(this._timerId), window.removeEventListener("zyna-genre", this._genreHandler);
|
|
18
|
+
}
|
|
19
|
+
attributeChangedCallback() {
|
|
20
|
+
this.isConnected && this._render();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns the raw string value of an attribute, or `fallback` if absent.
|
|
24
|
+
* @param {string} name
|
|
25
|
+
* @param {*} fallback
|
|
26
|
+
* @returns {string|*}
|
|
27
|
+
*/
|
|
28
|
+
_attr(t, e) {
|
|
29
|
+
const i = this.getAttribute(t);
|
|
30
|
+
return i !== null ? i : e;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns the JSON-parsed value of an attribute, or `fallback` if absent or unparseable.
|
|
34
|
+
* @param {string} name
|
|
35
|
+
* @param {*} fallback
|
|
36
|
+
* @returns {*}
|
|
37
|
+
*/
|
|
38
|
+
_json(t, e) {
|
|
39
|
+
const i = this.getAttribute(t);
|
|
40
|
+
if (i === null) return e;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(i);
|
|
43
|
+
} catch {
|
|
44
|
+
return e;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A stable, per-instance unique string for use in SVG `id` / `url()` references.
|
|
49
|
+
* Uses `crypto.randomUUID()` when available, falling back to `Math.random()`.
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
get _uid() {
|
|
53
|
+
return this.__uid || (this.__uid = typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID().slice(0, 8) : Math.random().toString(36).slice(2, 10)), this.__uid;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Logs a dev-friendly warning when a chart is mounted with no data.
|
|
57
|
+
* Silenced in production by a `data-silent` attribute on the element.
|
|
58
|
+
* @param {string} tag Custom element tag name e.g. 'zyna-waffle'
|
|
59
|
+
*/
|
|
60
|
+
_warnEmpty(t) {
|
|
61
|
+
this.hasAttribute("data-silent") || console.warn(`[${t}] No data provided. Add a \`data\` attribute with a JSON array.`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Formats a numeric value using a D3-style format string.
|
|
65
|
+
* Supports: '$' prefix, ',' thousands separator, '.Nf' decimals, '%' (×100 + suffix).
|
|
66
|
+
* Returns the value unchanged if no format string is provided.
|
|
67
|
+
* @param {number|string} value
|
|
68
|
+
* @param {string} fmt e.g. '$,.0f' | ',.2f' | '.1%' | ''
|
|
69
|
+
* @returns {string}
|
|
70
|
+
*/
|
|
71
|
+
_fmt(t, e) {
|
|
72
|
+
if (!e) return t;
|
|
73
|
+
const i = Number(t);
|
|
74
|
+
if (isNaN(i)) return String(t);
|
|
75
|
+
const r = e.includes("%"), d = e.includes("$"), o = e.includes(","), s = e.match(/\.(\d+)/), n = s ? parseInt(s[1]) : r ? 1 : 0, a = r ? i * 100 : i, c = o ? a.toLocaleString("en-US", { minimumFractionDigits: n, maximumFractionDigits: n }) : a.toFixed(n);
|
|
76
|
+
return (d ? "$" : "") + c + (r ? "%" : "");
|
|
77
|
+
}
|
|
78
|
+
_brand() {
|
|
79
|
+
return getComputedStyle(document.documentElement).getPropertyValue("--zyna").trim() || "#C9A84C";
|
|
80
|
+
}
|
|
81
|
+
_brandDark() {
|
|
82
|
+
return getComputedStyle(document.documentElement).getPropertyValue("--zyna-dark").trim() || "#7A6230";
|
|
83
|
+
}
|
|
84
|
+
_render() {
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
l as Z
|
|
89
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";class h extends HTMLElement{connectedCallback(){this._lastW=0,this._rafId=null,this._timerId=null,this._genreHandler=()=>this._render(),window.addEventListener("zyna-genre",this._genreHandler),this._ro=new ResizeObserver(t=>{var r;const e=((r=t[0])==null?void 0:r.contentRect.width)??this.clientWidth;if(Math.abs(e-this._lastW)<3)return;const i=this._lastW===0;this._lastW=e,this._rafId&&cancelAnimationFrame(this._rafId),this._rafId=requestAnimationFrame(()=>{this._rafId=null,clearTimeout(this._timerId),i?this._render():this._timerId=setTimeout(()=>this._render(),150)})}),this._ro.observe(this),requestAnimationFrame(()=>{this._lastW===0&&(this._lastW=this.clientWidth,this._render())})}disconnectedCallback(){var t;(t=this._ro)==null||t.disconnect(),this._rafId&&cancelAnimationFrame(this._rafId),this._timerId&&clearTimeout(this._timerId),window.removeEventListener("zyna-genre",this._genreHandler)}attributeChangedCallback(){this.isConnected&&this._render()}_attr(t,e){const i=this.getAttribute(t);return i!==null?i:e}_json(t,e){const i=this.getAttribute(t);if(i===null)return e;try{return JSON.parse(i)}catch{return e}}get _uid(){return this.__uid||(this.__uid=typeof crypto<"u"&&crypto.randomUUID?crypto.randomUUID().slice(0,8):Math.random().toString(36).slice(2,10)),this.__uid}_warnEmpty(t){this.hasAttribute("data-silent")||console.warn(`[${t}] No data provided. Add a \`data\` attribute with a JSON array.`)}_fmt(t,e){if(!e)return t;const i=Number(t);if(isNaN(i))return String(t);const r=e.includes("%"),d=e.includes("$"),o=e.includes(","),s=e.match(/\.(\d+)/),n=s?parseInt(s[1]):r?1:0,a=r?i*100:i,c=o?a.toLocaleString("en-US",{minimumFractionDigits:n,maximumFractionDigits:n}):a.toFixed(n);return(d?"$":"")+c+(r?"%":"")}_brand(){return getComputedStyle(document.documentElement).getPropertyValue("--zyna").trim()||"#C9A84C"}_brandDark(){return getComputedStyle(document.documentElement).getPropertyValue("--zyna-dark").trim()||"#7A6230"}_render(){}}exports.ZynaChart=h;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const H=require("../base-DyLOr2iL.cjs"),d=require("d3-selection"),T=require("d3-array"),W=require("d3-scale");class y extends H.ZynaChart{static get observedAttributes(){return["data","color","theme","highlight","muted-color","height","show-values","label-format","ticks"]}_render(){var g;const o=this._json("data",[]),b=this._attr("color",this._brand()),f=this._attr("muted-color",""),k=f||this._brandDark(),_=f||"#8A8478",v=this._attr("highlight","")||((g=o[0])==null?void 0:g.label)||"",w=this._attr("label-format",""),A=t=>this._fmt(t,w),M=this._attr("show-values","true")!=="false",u=parseInt(this._attr("height","0")),E=parseInt(this._attr("ticks","5")),z=this._attr("theme","dark")!=="light"?"#F0EBE0":"#1A1A20";if(!o.length){this._warnEmpty("zyna-lollipop");return}const S=(T.max(o,t=>t.value)||1)*1.1,l=this.clientWidth||420,$=Math.max(44,Math.min(70,l*.14)),r=u>0?u:Math.max(200,o.length*$+60),e={left:Math.max(60,l*.18),right:Math.max(50,l*.15),top:10,bottom:28},j=l-e.left-e.right,q=r-e.top-e.bottom,m=W.scaleLinear().domain([0,S]).range([0,j]),i=Math.max(9,l*.022),L=Math.max(11,l*.026);let n=d.select(this).select("svg");n.empty()&&(n=d.select(this).append("svg").style("display","block")),n.attr("viewBox",`0 0 ${l} ${r}`).attr("width",l).attr("height",r);const V=m.ticks(E);n.selectAll("g.ll-tick").data(V,t=>t).join(t=>{const a=t.append("g").attr("class","ll-tick");return a.append("line").attr("class","ll-tick-line"),a.append("text").attr("class","ll-tick-label"),a}).each(function(t){const a=d.select(this),s=e.left+m(t);a.select(".ll-tick-line").attr("x1",s).attr("x2",s).attr("y1",e.top).attr("y2",r-e.bottom+4).attr("stroke","#1E1E24").attr("stroke-width",.8),a.select(".ll-tick-label").attr("x",s).attr("y",r-e.bottom+16).attr("text-anchor","middle").attr("font-family","monospace").attr("font-size",`${i}px`).attr("fill","#5A5050").text(t)}),n.selectAll("g.ll-row").data(o,t=>t.label).join(t=>{const a=t.append("g").attr("class","ll-row");return a.append("line").attr("class","ll-stem"),a.append("circle").attr("class","ll-dot"),a.append("text").attr("class","ll-label"),a.append("text").attr("class","ll-value"),a}).each(function(t,a){const s=d.select(this),c=e.top+(a+.5)*(q/o.length),p=e.left+m(t.value),h=t.label===v,x=h?b:k,C=h?z:_;s.select(".ll-stem").attr("x1",e.left).attr("x2",p).attr("y1",c).attr("y2",c).attr("stroke",x).attr("stroke-width",h?1.5:1),s.select(".ll-dot").attr("cx",p).attr("cy",c).attr("r",h?7:5).attr("fill",x),s.select(".ll-label").attr("x",e.left-6).attr("y",c+i*.4).attr("text-anchor","end").attr("font-size",`${L}px`).attr("fill",C).text(t.label),s.select(".ll-value").attr("display",M?null:"none").attr("x",p+10).attr("y",c+i*.4).attr("font-family","monospace").attr("font-size",`${i}px`).attr("fill",x).text(A(t.value))})}}customElements.get("zyna-lollipop")||customElements.define("zyna-lollipop",y);exports.ZynaLollipop=y;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Z as W } from "../base-CaP9Us8w.js";
|
|
2
|
+
import { select as m } from "d3-selection";
|
|
3
|
+
import { max as Z } from "d3-array";
|
|
4
|
+
import { scaleLinear as B } from "d3-scale";
|
|
5
|
+
class I extends W {
|
|
6
|
+
static get observedAttributes() {
|
|
7
|
+
return ["data", "color", "theme", "highlight", "muted-color", "height", "show-values", "label-format", "ticks"];
|
|
8
|
+
}
|
|
9
|
+
_render() {
|
|
10
|
+
var u;
|
|
11
|
+
const o = this._json("data", []), y = this._attr("color", this._brand()), f = this._attr("muted-color", ""), b = f || this._brandDark(), k = f || "#8A8478", _ = this._attr("highlight", "") || ((u = o[0]) == null ? void 0 : u.label) || "", v = this._attr("label-format", ""), w = (t) => this._fmt(t, v), A = this._attr("show-values", "true") !== "false", g = parseInt(this._attr("height", "0")), M = parseInt(this._attr("ticks", "5")), E = this._attr("theme", "dark") !== "light" ? "#F0EBE0" : "#1A1A20";
|
|
12
|
+
if (!o.length) {
|
|
13
|
+
this._warnEmpty("zyna-lollipop");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const z = (Z(o, (t) => t.value) || 1) * 1.1, e = this.clientWidth || 420, $ = Math.max(44, Math.min(70, e * 0.14)), r = g > 0 ? g : Math.max(200, o.length * $ + 60), l = { left: Math.max(60, e * 0.18), right: Math.max(50, e * 0.15), top: 10, bottom: 28 }, V = e - l.left - l.right, j = r - l.top - l.bottom, p = B().domain([0, z]).range([0, V]), i = Math.max(9, e * 0.022), C = Math.max(11, e * 0.026);
|
|
17
|
+
let n = m(this).select("svg");
|
|
18
|
+
n.empty() && (n = m(this).append("svg").style("display", "block")), n.attr("viewBox", `0 0 ${e} ${r}`).attr("width", e).attr("height", r);
|
|
19
|
+
const H = p.ticks(M);
|
|
20
|
+
n.selectAll("g.ll-tick").data(H, (t) => t).join((t) => {
|
|
21
|
+
const a = t.append("g").attr("class", "ll-tick");
|
|
22
|
+
return a.append("line").attr("class", "ll-tick-line"), a.append("text").attr("class", "ll-tick-label"), a;
|
|
23
|
+
}).each(function(t) {
|
|
24
|
+
const a = m(this), s = l.left + p(t);
|
|
25
|
+
a.select(".ll-tick-line").attr("x1", s).attr("x2", s).attr("y1", l.top).attr("y2", r - l.bottom + 4).attr("stroke", "#1E1E24").attr("stroke-width", 0.8), a.select(".ll-tick-label").attr("x", s).attr("y", r - l.bottom + 16).attr("text-anchor", "middle").attr("font-family", "monospace").attr("font-size", `${i}px`).attr("fill", "#5A5050").text(t);
|
|
26
|
+
}), n.selectAll("g.ll-row").data(o, (t) => t.label).join((t) => {
|
|
27
|
+
const a = t.append("g").attr("class", "ll-row");
|
|
28
|
+
return a.append("line").attr("class", "ll-stem"), a.append("circle").attr("class", "ll-dot"), a.append("text").attr("class", "ll-label"), a.append("text").attr("class", "ll-value"), a;
|
|
29
|
+
}).each(function(t, a) {
|
|
30
|
+
const s = m(this), c = l.top + (a + 0.5) * (j / o.length), d = l.left + p(t.value), h = t.label === _, x = h ? y : b, L = h ? E : k;
|
|
31
|
+
s.select(".ll-stem").attr("x1", l.left).attr("x2", d).attr("y1", c).attr("y2", c).attr("stroke", x).attr("stroke-width", h ? 1.5 : 1), s.select(".ll-dot").attr("cx", d).attr("cy", c).attr("r", h ? 7 : 5).attr("fill", x), s.select(".ll-label").attr("x", l.left - 6).attr("y", c + i * 0.4).attr("text-anchor", "end").attr("font-size", `${C}px`).attr("fill", L).text(t.label), s.select(".ll-value").attr("display", A ? null : "none").attr("x", d + 10).attr("y", c + i * 0.4).attr("font-family", "monospace").attr("font-size", `${i}px`).attr("fill", x).text(w(t.value));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
customElements.get("zyna-lollipop") || customElements.define("zyna-lollipop", I);
|
|
36
|
+
export {
|
|
37
|
+
I as ZynaLollipop
|
|
38
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("../base-DyLOr2iL.cjs"),b=require("d3-selection"),O=require("d3-array"),W=require("d3-shape");class C extends N.ZynaChart{static get observedAttributes(){return["data","color","theme","height","show-values","label-format"]}_render(){const i=this._json("data",[]),R=this._attr("color",this._brand()),p=this._attr("theme","dark")!=="light",S=this._attr("label-format",""),j=t=>this._fmt(t,S),B=this._attr("show-values","true")!=="false",v=parseInt(this._attr("height","0")),I=p?"#F0EBE0":"#1A1A20",$=p?"#0C0C0F":"#FFFFFF";if(!i.length){this._warnEmpty("zyna-nightingale");return}const e=this.clientWidth||700,f=v>0?v:Math.max(400,e*.8);let s=b.select(this).select("svg");s.empty()&&(s=b.select(this).append("svg").style("display","block")),s.attr("viewBox",`0 0 ${e} ${f}`).attr("width",e).attr("height",f);const n=e/2,r=f/2,x=Math.min(n,r)*.52,P=O.max(i,t=>t.value)||1,V=i.length,A=2*Math.PI/V,_=x+Math.max(70,e*.14),k=Math.max(6,x*.06),h=Math.max(10,e*.015),Z=Math.max(12,e*.018);s.selectAll("g.ng-sector").data(i,t=>t.label).join(t=>{const a=t.append("g").attr("class","ng-sector");return a.append("path").attr("class","ng-arc"),a.append("text").attr("class","ng-label"),a.append("text").attr("class","ng-value"),a.append("polyline").attr("class","ng-leader"),a.append("circle").attr("class","ng-dot"),a}).each(function(t,a){const l=b.select(this),y=a*A-Math.PI/2,w=y+A,M=x*Math.sqrt(t.value/P),c=(y+w)/2,g=t.color||R;l.select(".ng-arc").attr("d",W.arc().innerRadius(k).outerRadius(M).startAngle(y).endAngle(w)).attr("transform",`translate(${n},${r})`).attr("fill",g).attr("stroke",$).attr("stroke-width",1.5);const E=n+(M+10)*Math.sin(c),F=r-(M+10)*Math.cos(c),d=n+_*Math.sin(c),m=r-_*Math.cos(c),o=Math.sin(c),q=o<-.1?"end":o>.1?"start":"middle",z=o>.1?6:o<-.1?-6:0;l.select(".ng-label").attr("x",d+z).attr("y",m-4).attr("text-anchor",q).attr("font-size",`${Z}px`).attr("fill",I).text(t.label),l.select(".ng-value").attr("display",B?null:"none").attr("x",d+z).attr("y",m+h+2).attr("text-anchor",q).attr("font-family","monospace").attr("font-size",`${h}px`).attr("fill",g).text(j(t.value)),l.select(".ng-leader").attr("points",`${d},${m+h+12} ${d-o*24},${m+h+12} ${E},${F}`).attr("fill","none").attr("stroke",g).attr("stroke-width",.8).attr("opacity",.5),l.select(".ng-dot").attr("cx",E).attr("cy",F).attr("r",3).attr("fill",g)});let u=s.select(".ng-cap");u.empty()&&(u=s.append("circle").attr("class","ng-cap")),u.attr("cx",n).attr("cy",r).attr("r",k*1.4).attr("fill",$).attr("stroke",p?"#2A2A30":"#E5E7EB").attr("stroke-width",1)}}customElements.get("zyna-nightingale")||customElements.define("zyna-nightingale",C);exports.ZynaNightingale=C;
|