@teamflojo/floimg-d3 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +175 -181
  3. package/package.json +12 -13
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Flojo, Inc.
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 CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  D3 data visualization generator for floimg using server-side rendering.
4
4
 
5
+ ## Standing on the Shoulders of Giants
6
+
7
+ This plugin is a thin wrapper around [D3.js](https://d3js.org/). We don't abstract or limit the underlying library—your render function has full access to D3's API.
8
+
9
+ - **Full D3 power**: Complete access to all D3 capabilities
10
+ - **Native API**: Write real D3 code, not a FloImg abstraction
11
+ - **Their docs are your docs**: See [D3 documentation](https://d3js.org/) and [D3 gallery](https://observablehq.com/@d3/gallery)
12
+
13
+ FloImg orchestrates the workflow (generate → transform → save). D3 does what it does best.
14
+
5
15
  ## Installation
6
16
 
7
17
  ```bash
@@ -11,41 +21,36 @@ npm install @teamflojo/floimg @teamflojo/floimg-d3
11
21
  ## Usage
12
22
 
13
23
  ```typescript
14
- import createClient from '@teamflojo/floimg';
15
- import d3viz from '@teamflojo/floimg-d3';
24
+ import createClient from "@teamflojo/floimg";
25
+ import d3viz from "@teamflojo/floimg-d3";
16
26
 
17
27
  const floimg = createClient();
18
28
  floimg.registerGenerator(d3viz());
19
29
 
20
30
  // Create a bar chart
21
31
  const chart = await floimg.generate({
22
- generator: 'd3',
32
+ generator: "d3",
23
33
  params: {
24
34
  width: 600,
25
35
  height: 400,
26
36
  render: (svg, d3, data) => {
27
37
  // Use D3 directly - full API available
28
- svg.selectAll('rect')
38
+ svg
39
+ .selectAll("rect")
29
40
  .data(data)
30
- .join('rect')
31
- .attr('x', (d, i) => i * 60)
32
- .attr('y', d => 400 - d.value * 3)
33
- .attr('width', 50)
34
- .attr('height', d => d.value * 3)
35
- .attr('fill', 'steelblue');
41
+ .join("rect")
42
+ .attr("x", (d, i) => i * 60)
43
+ .attr("y", (d) => 400 - d.value * 3)
44
+ .attr("width", 50)
45
+ .attr("height", (d) => d.value * 3)
46
+ .attr("fill", "steelblue");
36
47
  },
37
- data: [
38
- { value: 30 },
39
- { value: 80 },
40
- { value: 45 },
41
- { value: 60 },
42
- { value: 20 }
43
- ]
44
- }
48
+ data: [{ value: 30 }, { value: 80 }, { value: 45 }, { value: 60 }, { value: 20 }],
49
+ },
45
50
  });
46
51
 
47
52
  // Upload to S3
48
- await floimg.save(chart, './output/bar.svg');
53
+ await floimg.save(chart, "./output/bar.svg");
49
54
  ```
50
55
 
51
56
  ## Examples
@@ -54,7 +59,7 @@ await floimg.save(chart, './output/bar.svg');
54
59
 
55
60
  ```typescript
56
61
  const barChart = await floimg.generate({
57
- generator: 'd3',
62
+ generator: "d3",
58
63
  params: {
59
64
  width: 800,
60
65
  height: 400,
@@ -63,41 +68,39 @@ const barChart = await floimg.generate({
63
68
  const width = 800 - margin.left - margin.right;
64
69
  const height = 400 - margin.top - margin.bottom;
65
70
 
66
- const g = svg.append('g')
67
- .attr('transform', `translate(${margin.left},${margin.top})`);
71
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
68
72
 
69
- const x = d3.scaleBand()
70
- .domain(data.map(d => d.name))
73
+ const x = d3
74
+ .scaleBand()
75
+ .domain(data.map((d) => d.name))
71
76
  .range([0, width])
72
77
  .padding(0.1);
73
78
 
74
- const y = d3.scaleLinear()
75
- .domain([0, d3.max(data, d => d.value)])
79
+ const y = d3
80
+ .scaleLinear()
81
+ .domain([0, d3.max(data, (d) => d.value)])
76
82
  .range([height, 0]);
77
83
 
78
- g.selectAll('rect')
84
+ g.selectAll("rect")
79
85
  .data(data)
80
- .join('rect')
81
- .attr('x', d => x(d.name))
82
- .attr('y', d => y(d.value))
83
- .attr('width', x.bandwidth())
84
- .attr('height', d => height - y(d.value))
85
- .attr('fill', 'steelblue');
86
-
87
- g.append('g')
88
- .attr('transform', `translate(0,${height})`)
89
- .call(d3.axisBottom(x));
90
-
91
- g.append('g')
92
- .call(d3.axisLeft(y));
86
+ .join("rect")
87
+ .attr("x", (d) => x(d.name))
88
+ .attr("y", (d) => y(d.value))
89
+ .attr("width", x.bandwidth())
90
+ .attr("height", (d) => height - y(d.value))
91
+ .attr("fill", "steelblue");
92
+
93
+ g.append("g").attr("transform", `translate(0,${height})`).call(d3.axisBottom(x));
94
+
95
+ g.append("g").call(d3.axisLeft(y));
93
96
  },
94
97
  data: [
95
- { name: 'Q1', value: 120 },
96
- { name: 'Q2', value: 200 },
97
- { name: 'Q3', value: 150 },
98
- { name: 'Q4', value: 170 }
99
- ]
100
- }
98
+ { name: "Q1", value: 120 },
99
+ { name: "Q2", value: 200 },
100
+ { name: "Q3", value: 150 },
101
+ { name: "Q4", value: 170 },
102
+ ],
103
+ },
101
104
  });
102
105
  ```
103
106
 
@@ -105,7 +108,7 @@ const barChart = await floimg.generate({
105
108
 
106
109
  ```typescript
107
110
  const lineChart = await floimg.generate({
108
- generator: 'd3',
111
+ generator: "d3",
109
112
  params: {
110
113
  width: 800,
111
114
  height: 400,
@@ -114,34 +117,33 @@ const lineChart = await floimg.generate({
114
117
  const width = 800 - margin.left - margin.right;
115
118
  const height = 400 - margin.top - margin.bottom;
116
119
 
117
- const g = svg.append('g')
118
- .attr('transform', `translate(${margin.left},${margin.top})`);
120
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
119
121
 
120
- const x = d3.scaleLinear()
122
+ const x = d3
123
+ .scaleLinear()
121
124
  .domain([0, data.length - 1])
122
125
  .range([0, width]);
123
126
 
124
- const y = d3.scaleLinear()
125
- .domain([0, d3.max(data, d => d.value)])
127
+ const y = d3
128
+ .scaleLinear()
129
+ .domain([0, d3.max(data, (d) => d.value)])
126
130
  .range([height, 0]);
127
131
 
128
- const line = d3.line()
132
+ const line = d3
133
+ .line()
129
134
  .x((d, i) => x(i))
130
- .y(d => y(d.value));
135
+ .y((d) => y(d.value));
131
136
 
132
- g.append('path')
137
+ g.append("path")
133
138
  .datum(data)
134
- .attr('fill', 'none')
135
- .attr('stroke', 'steelblue')
136
- .attr('stroke-width', 2)
137
- .attr('d', line);
139
+ .attr("fill", "none")
140
+ .attr("stroke", "steelblue")
141
+ .attr("stroke-width", 2)
142
+ .attr("d", line);
138
143
 
139
- g.append('g')
140
- .attr('transform', `translate(0,${height})`)
141
- .call(d3.axisBottom(x));
144
+ g.append("g").attr("transform", `translate(0,${height})`).call(d3.axisBottom(x));
142
145
 
143
- g.append('g')
144
- .call(d3.axisLeft(y));
146
+ g.append("g").call(d3.axisLeft(y));
145
147
  },
146
148
  data: [
147
149
  { value: 30 },
@@ -149,9 +151,9 @@ const lineChart = await floimg.generate({
149
151
  { value: 45 },
150
152
  { value: 80 },
151
153
  { value: 70 },
152
- { value: 90 }
153
- ]
154
- }
154
+ { value: 90 },
155
+ ],
156
+ },
155
157
  });
156
158
  ```
157
159
 
@@ -159,7 +161,7 @@ const lineChart = await floimg.generate({
159
161
 
160
162
  ```typescript
161
163
  const pieChart = await floimg.generate({
162
- generator: 'd3',
164
+ generator: "d3",
163
165
  params: {
164
166
  width: 500,
165
167
  height: 500,
@@ -168,39 +170,34 @@ const pieChart = await floimg.generate({
168
170
  const height = 500;
169
171
  const radius = Math.min(width, height) / 2;
170
172
 
171
- const g = svg.append('g')
172
- .attr('transform', `translate(${width / 2},${height / 2})`);
173
+ const g = svg.append("g").attr("transform", `translate(${width / 2},${height / 2})`);
173
174
 
174
175
  const color = d3.scaleOrdinal(d3.schemeCategory10);
175
176
 
176
- const pie = d3.pie()
177
- .value(d => d.value);
177
+ const pie = d3.pie().value((d) => d.value);
178
178
 
179
- const arc = d3.arc()
180
- .innerRadius(0)
181
- .outerRadius(radius);
179
+ const arc = d3.arc().innerRadius(0).outerRadius(radius);
182
180
 
183
- const arcs = g.selectAll('arc')
184
- .data(pie(data))
185
- .join('g')
186
- .attr('class', 'arc');
181
+ const arcs = g.selectAll("arc").data(pie(data)).join("g").attr("class", "arc");
187
182
 
188
- arcs.append('path')
189
- .attr('d', arc)
190
- .attr('fill', (d, i) => color(i));
183
+ arcs
184
+ .append("path")
185
+ .attr("d", arc)
186
+ .attr("fill", (d, i) => color(i));
191
187
 
192
- arcs.append('text')
193
- .attr('transform', d => `translate(${arc.centroid(d)})`)
194
- .attr('text-anchor', 'middle')
195
- .text(d => d.data.label);
188
+ arcs
189
+ .append("text")
190
+ .attr("transform", (d) => `translate(${arc.centroid(d)})`)
191
+ .attr("text-anchor", "middle")
192
+ .text((d) => d.data.label);
196
193
  },
197
194
  data: [
198
- { label: 'A', value: 30 },
199
- { label: 'B', value: 70 },
200
- { label: 'C', value: 45 },
201
- { label: 'D', value: 60 }
202
- ]
203
- }
195
+ { label: "A", value: 30 },
196
+ { label: "B", value: 70 },
197
+ { label: "C", value: 45 },
198
+ { label: "D", value: 60 },
199
+ ],
200
+ },
204
201
  });
205
202
  ```
206
203
 
@@ -208,7 +205,7 @@ const pieChart = await floimg.generate({
208
205
 
209
206
  ```typescript
210
207
  const scatterPlot = await floimg.generate({
211
- generator: 'd3',
208
+ generator: "d3",
212
209
  params: {
213
210
  width: 600,
214
211
  height: 400,
@@ -217,41 +214,39 @@ const scatterPlot = await floimg.generate({
217
214
  const width = 600 - margin.left - margin.right;
218
215
  const height = 400 - margin.top - margin.bottom;
219
216
 
220
- const g = svg.append('g')
221
- .attr('transform', `translate(${margin.left},${margin.top})`);
217
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
222
218
 
223
- const x = d3.scaleLinear()
224
- .domain([0, d3.max(data, d => d.x)])
219
+ const x = d3
220
+ .scaleLinear()
221
+ .domain([0, d3.max(data, (d) => d.x)])
225
222
  .range([0, width]);
226
223
 
227
- const y = d3.scaleLinear()
228
- .domain([0, d3.max(data, d => d.y)])
224
+ const y = d3
225
+ .scaleLinear()
226
+ .domain([0, d3.max(data, (d) => d.y)])
229
227
  .range([height, 0]);
230
228
 
231
- g.selectAll('circle')
229
+ g.selectAll("circle")
232
230
  .data(data)
233
- .join('circle')
234
- .attr('cx', d => x(d.x))
235
- .attr('cy', d => y(d.y))
236
- .attr('r', 5)
237
- .attr('fill', 'steelblue')
238
- .attr('opacity', 0.7);
239
-
240
- g.append('g')
241
- .attr('transform', `translate(0,${height})`)
242
- .call(d3.axisBottom(x));
243
-
244
- g.append('g')
245
- .call(d3.axisLeft(y));
231
+ .join("circle")
232
+ .attr("cx", (d) => x(d.x))
233
+ .attr("cy", (d) => y(d.y))
234
+ .attr("r", 5)
235
+ .attr("fill", "steelblue")
236
+ .attr("opacity", 0.7);
237
+
238
+ g.append("g").attr("transform", `translate(0,${height})`).call(d3.axisBottom(x));
239
+
240
+ g.append("g").call(d3.axisLeft(y));
246
241
  },
247
242
  data: [
248
243
  { x: 10, y: 20 },
249
244
  { x: 20, y: 40 },
250
245
  { x: 30, y: 25 },
251
246
  { x: 40, y: 60 },
252
- { x: 50, y: 45 }
253
- ]
254
- }
247
+ { x: 50, y: 45 },
248
+ ],
249
+ },
255
250
  });
256
251
  ```
257
252
 
@@ -259,7 +254,7 @@ const scatterPlot = await floimg.generate({
259
254
 
260
255
  ```typescript
261
256
  const areaChart = await floimg.generate({
262
- generator: 'd3',
257
+ generator: "d3",
263
258
  params: {
264
259
  width: 800,
265
260
  height: 400,
@@ -268,34 +263,29 @@ const areaChart = await floimg.generate({
268
263
  const width = 800 - margin.left - margin.right;
269
264
  const height = 400 - margin.top - margin.bottom;
270
265
 
271
- const g = svg.append('g')
272
- .attr('transform', `translate(${margin.left},${margin.top})`);
266
+ const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);
273
267
 
274
- const x = d3.scaleLinear()
268
+ const x = d3
269
+ .scaleLinear()
275
270
  .domain([0, data.length - 1])
276
271
  .range([0, width]);
277
272
 
278
- const y = d3.scaleLinear()
279
- .domain([0, d3.max(data, d => d.value)])
273
+ const y = d3
274
+ .scaleLinear()
275
+ .domain([0, d3.max(data, (d) => d.value)])
280
276
  .range([height, 0]);
281
277
 
282
- const area = d3.area()
278
+ const area = d3
279
+ .area()
283
280
  .x((d, i) => x(i))
284
281
  .y0(height)
285
- .y1(d => y(d.value));
282
+ .y1((d) => y(d.value));
286
283
 
287
- g.append('path')
288
- .datum(data)
289
- .attr('fill', 'steelblue')
290
- .attr('opacity', 0.7)
291
- .attr('d', area);
284
+ g.append("path").datum(data).attr("fill", "steelblue").attr("opacity", 0.7).attr("d", area);
292
285
 
293
- g.append('g')
294
- .attr('transform', `translate(0,${height})`)
295
- .call(d3.axisBottom(x));
286
+ g.append("g").attr("transform", `translate(0,${height})`).call(d3.axisBottom(x));
296
287
 
297
- g.append('g')
298
- .call(d3.axisLeft(y));
288
+ g.append("g").call(d3.axisLeft(y));
299
289
  },
300
290
  data: [
301
291
  { value: 30 },
@@ -303,9 +293,9 @@ const areaChart = await floimg.generate({
303
293
  { value: 45 },
304
294
  { value: 80 },
305
295
  { value: 70 },
306
- { value: 90 }
307
- ]
308
- }
296
+ { value: 90 },
297
+ ],
298
+ },
309
299
  });
310
300
  ```
311
301
 
@@ -313,7 +303,7 @@ const areaChart = await floimg.generate({
313
303
 
314
304
  ```typescript
315
305
  const heatmap = await floimg.generate({
316
- generator: 'd3',
306
+ generator: "d3",
317
307
  params: {
318
308
  width: 600,
319
309
  height: 400,
@@ -322,25 +312,26 @@ const heatmap = await floimg.generate({
322
312
  const rows = data.length;
323
313
  const cols = data[0].length;
324
314
 
325
- const color = d3.scaleSequential(d3.interpolateBlues)
326
- .domain([0, d3.max(data.flat())]);
315
+ const color = d3.scaleSequential(d3.interpolateBlues).domain([0, d3.max(data.flat())]);
327
316
 
328
317
  for (let i = 0; i < rows; i++) {
329
318
  for (let j = 0; j < cols; j++) {
330
- svg.append('rect')
331
- .attr('x', j * cellSize)
332
- .attr('y', i * cellSize)
333
- .attr('width', cellSize)
334
- .attr('height', cellSize)
335
- .attr('fill', color(data[i][j]))
336
- .attr('stroke', 'white');
337
-
338
- svg.append('text')
339
- .attr('x', j * cellSize + cellSize / 2)
340
- .attr('y', i * cellSize + cellSize / 2)
341
- .attr('text-anchor', 'middle')
342
- .attr('dominant-baseline', 'middle')
343
- .attr('fill', data[i][j] > 5 ? 'white' : 'black')
319
+ svg
320
+ .append("rect")
321
+ .attr("x", j * cellSize)
322
+ .attr("y", i * cellSize)
323
+ .attr("width", cellSize)
324
+ .attr("height", cellSize)
325
+ .attr("fill", color(data[i][j]))
326
+ .attr("stroke", "white");
327
+
328
+ svg
329
+ .append("text")
330
+ .attr("x", j * cellSize + cellSize / 2)
331
+ .attr("y", i * cellSize + cellSize / 2)
332
+ .attr("text-anchor", "middle")
333
+ .attr("dominant-baseline", "middle")
334
+ .attr("fill", data[i][j] > 5 ? "white" : "black")
344
335
  .text(data[i][j]);
345
336
  }
346
337
  }
@@ -349,31 +340,33 @@ const heatmap = await floimg.generate({
349
340
  [1, 3, 5, 7],
350
341
  [2, 4, 6, 8],
351
342
  [9, 7, 5, 3],
352
- [8, 6, 4, 2]
353
- ]
354
- }
343
+ [8, 6, 4, 2],
344
+ ],
345
+ },
355
346
  });
356
347
  ```
357
348
 
358
349
  ## Parameters
359
350
 
360
- | Parameter | Type | Default | Description |
361
- |-----------|------|---------|-------------|
362
- | `width` | number | 800 | Output width in pixels |
363
- | `height` | number | 600 | Output height in pixels |
364
- | `backgroundColor` | string | 'white' | Background color |
365
- | `render` | function | *required* | Function that receives (svg, d3, data) |
366
- | `renderString` | string | - | String version of render function (for serialization) |
367
- | `data` | any | [] | Data to pass to render function |
351
+ | Parameter | Type | Default | Description |
352
+ | ----------------- | -------- | ---------- | ----------------------------------------------------- |
353
+ | `width` | number | 800 | Output width in pixels |
354
+ | `height` | number | 600 | Output height in pixels |
355
+ | `backgroundColor` | string | 'white' | Background color |
356
+ | `render` | function | _required_ | Function that receives (svg, d3, data) |
357
+ | `renderString` | string | - | String version of render function (for serialization) |
358
+ | `data` | any | [] | Data to pass to render function |
368
359
 
369
360
  ## Configuration
370
361
 
371
362
  ```typescript
372
- floimg.registerGenerator(d3viz({
373
- width: 1000, // Default width
374
- height: 600, // Default height
375
- backgroundColor: '#f0f0f0' // Default background
376
- }));
363
+ floimg.registerGenerator(
364
+ d3viz({
365
+ width: 1000, // Default width
366
+ height: 600, // Default height
367
+ backgroundColor: "#f0f0f0", // Default background
368
+ })
369
+ );
377
370
  ```
378
371
 
379
372
  ## Features
@@ -387,6 +380,7 @@ floimg.registerGenerator(d3viz({
387
380
  ## D3 Documentation
388
381
 
389
382
  For full D3 capabilities and examples:
383
+
390
384
  - https://d3js.org/
391
385
  - https://observablehq.com/@d3/gallery
392
386
 
@@ -403,9 +397,9 @@ For full D3 capabilities and examples:
403
397
  ```typescript
404
398
  // Generate multiple charts for a report
405
399
  const charts = await Promise.all([
406
- floimg.generate({ generator: 'd3', params: salesChartConfig }),
407
- floimg.generate({ generator: 'd3', params: revenueChartConfig }),
408
- floimg.generate({ generator: 'd3', params: growthChartConfig })
400
+ floimg.generate({ generator: "d3", params: salesChartConfig }),
401
+ floimg.generate({ generator: "d3", params: revenueChartConfig }),
402
+ floimg.generate({ generator: "d3", params: growthChartConfig }),
409
403
  ]);
410
404
  ```
411
405
 
@@ -416,26 +410,26 @@ const charts = await Promise.all([
416
410
  setInterval(async () => {
417
411
  const liveData = await fetchLiveData();
418
412
  const chart = await floimg.generate({
419
- generator: 'd3',
413
+ generator: "d3",
420
414
  params: {
421
415
  render: createChartRenderer(),
422
- data: liveData
423
- }
416
+ data: liveData,
417
+ },
424
418
  });
425
- await floimg.save(chart, './output/dashboard-live.svg');
419
+ await floimg.save(chart, "./output/dashboard-live.svg");
426
420
  }, 60000);
427
421
  ```
428
422
 
429
423
  ### API Endpoints
430
424
 
431
425
  ```typescript
432
- app.get('/api/chart/:type', async (req, res) => {
426
+ app.get("/api/chart/:type", async (req, res) => {
433
427
  const data = await fetchData(req.params.type);
434
428
  const chart = await floimg.generate({
435
- generator: 'd3',
436
- params: { render: getRenderer(req.params.type), data }
429
+ generator: "d3",
430
+ params: { render: getRenderer(req.params.type), data },
437
431
  });
438
- res.type('image/svg+xml').send(chart.bytes);
432
+ res.type("image/svg+xml").send(chart.bytes);
439
433
  });
440
434
  ```
441
435
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamflojo/floimg-d3",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "D3 data visualization generator for floimg using server-side rendering",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,14 +16,6 @@
16
16
  "README.md",
17
17
  "LICENSE"
18
18
  ],
19
- "scripts": {
20
- "build": "tsc",
21
- "dev": "tsc --watch",
22
- "test": "vitest",
23
- "typecheck": "tsc --noEmit",
24
- "clean": "rm -rf dist",
25
- "prepublishOnly": "npm run build"
26
- },
27
19
  "keywords": [
28
20
  "floimg",
29
21
  "d3",
@@ -40,7 +32,7 @@
40
32
  "directory": "packages/floimg-d3"
41
33
  },
42
34
  "peerDependencies": {
43
- "@teamflojo/floimg": "^0.1.0"
35
+ "@teamflojo/floimg": "^0.8.0"
44
36
  },
45
37
  "dependencies": {
46
38
  "d3": "^7.9.0",
@@ -50,11 +42,18 @@
50
42
  "@types/d3": "^7.4.3",
51
43
  "@types/jsdom": "^21.1.7",
52
44
  "@types/node": "^22.10.2",
53
- "@teamflojo/floimg": "workspace:*",
54
45
  "typescript": "^5.7.2",
55
- "vitest": "^2.1.8"
46
+ "vitest": "^2.1.8",
47
+ "@teamflojo/floimg": "0.9.0"
56
48
  },
57
49
  "engines": {
58
50
  "node": ">=18.0.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc",
54
+ "dev": "tsc --watch",
55
+ "test": "vitest --run",
56
+ "typecheck": "tsc --noEmit",
57
+ "clean": "rm -rf dist"
59
58
  }
60
- }
59
+ }