@hellobetterdigitalnz/betterui 0.0.3-291 → 0.0.3-292

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hellobetterdigitalnz/betterui",
3
- "version": "0.0.3-291",
3
+ "version": "0.0.3-292",
4
4
  "type": "module",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -10,11 +10,13 @@ import {
10
10
  import "./GanttChart.scss";
11
11
  import { DotsSixVertical } from "../../Icons";
12
12
 
13
+ // -------------------- Types --------------------
14
+
13
15
  type GanttTask = {
14
16
  id: string;
15
17
  name: string;
16
- start: string;
17
- end: string;
18
+ start: string; // ISO
19
+ end: string; // ISO
18
20
  color?: string;
19
21
  user?: string;
20
22
  };
@@ -24,6 +26,8 @@ type GanttChartProps = {
24
26
  onChange?: (tasks: GanttTask[]) => void;
25
27
  };
26
28
 
29
+ // -------------------- Utils --------------------
30
+
27
31
  function dateToMinuteIndex(base: Date, d: Date) {
28
32
  return differenceInMinutes(d, base);
29
33
  }
@@ -36,13 +40,16 @@ function clamp(n: number, min: number, max: number) {
36
40
  return Math.min(max, Math.max(min, n));
37
41
  }
38
42
 
43
+ // -------------------- Component --------------------
44
+
39
45
  export default function GanttChart({ tasks: initialTasks, onChange }: GanttChartProps) {
40
46
  const [currentDay, setCurrentDay] = useState<Date>(startOfDay(new Date()));
41
47
  const startDate = startOfDay(currentDay);
42
48
  const totalDays = 1;
43
- const daysRef = useRef<HTMLDivElement>(null);
44
- const [cellSize, setCellSize] = useState<number>(0);
45
-
49
+
50
+ // Use header hours for sizing (stable across rows). Avoid a shared ref across many rows.
51
+ const headerHoursRef = useRef<HTMLDivElement>(null);
52
+ const [cellSize, setCellSize] = useState<number>(60); // default aligns with CSS min-width
46
53
 
47
54
  const [tasks, setTasks] = useState<GanttTask[]>(
48
55
  initialTasks ?? [
@@ -52,15 +59,15 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
52
59
  start: "2025-08-27T05:30:00",
53
60
  end: "2025-08-27T10:30:00",
54
61
  color: "blue",
55
- user: "Alice"
62
+ user: "Alice",
56
63
  },
57
64
  {
58
65
  id: "2",
59
66
  name: "Development",
60
67
  start: "2025-08-27T09:45:00",
61
- end: "2025-08-17T27:30:00",
68
+ end: "2025-08-27T17:30:00", // FIX: valid 24h time and correct date
62
69
  color: "green",
63
- user: "Bob"
70
+ user: "Bob",
64
71
  },
65
72
  {
66
73
  id: "3",
@@ -68,7 +75,7 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
68
75
  start: "2025-08-27T08:10:00",
69
76
  end: "2025-08-27T09:40:00",
70
77
  color: "orange",
71
- user: "Charlie"
78
+ user: "Charlie",
72
79
  },
73
80
  {
74
81
  id: "4",
@@ -76,7 +83,7 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
76
83
  start: "2025-08-27T08:10:00",
77
84
  end: "2025-08-27T09:40:00",
78
85
  color: "red",
79
- user: "Mamudu"
86
+ user: "Mamudu",
80
87
  },
81
88
  {
82
89
  id: "5",
@@ -84,8 +91,8 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
84
91
  start: "2025-08-27T08:10:00",
85
92
  end: "2025-08-27T09:40:00",
86
93
  color: "black",
87
- user: ""
88
- }
94
+ user: "",
95
+ },
89
96
  ]
90
97
  );
91
98
 
@@ -93,10 +100,10 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
93
100
  taskId: string;
94
101
  x: number;
95
102
  y: number;
103
+ rowUser: string;
96
104
  }>(null);
97
105
 
98
- const minuteWidth = cellSize / 60;
99
-
106
+ const minuteWidth = useMemo(() => (cellSize > 0 ? cellSize / 60 : 1), [cellSize]);
100
107
  const pxToMinutes = useCallback((px: number) => px / minuteWidth, [minuteWidth]);
101
108
  const minutesToPx = useCallback((minutes: number) => minutes * minuteWidth, [minuteWidth]);
102
109
 
@@ -106,11 +113,9 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
106
113
 
107
114
  useEffect(() => {
108
115
  const updateSize = () => {
109
- if (daysRef.current) {
110
- const firstCell = daysRef.current.querySelector<HTMLDivElement>("[date-cell]");
111
- if (firstCell) {
112
- setCellSize(firstCell.offsetWidth);
113
- }
116
+ const firstHour = headerHoursRef.current?.querySelector<HTMLDivElement>(".hour");
117
+ if (firstHour) {
118
+ setCellSize(firstHour.offsetWidth);
114
119
  }
115
120
  };
116
121
 
@@ -119,6 +124,12 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
119
124
  return () => window.removeEventListener("resize", updateSize);
120
125
  }, []);
121
126
 
127
+ // Keep consumer in sync without stale closures
128
+ useEffect(() => {
129
+ if (onChange) onChange(tasks);
130
+ }, [tasks, onChange]);
131
+
132
+ // Drag state
122
133
  const dragState = useRef<null | {
123
134
  mode: "move" | "resize-start" | "resize-end";
124
135
  taskId: string;
@@ -128,14 +139,15 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
128
139
  originUser?: string;
129
140
  }>(null);
130
141
 
131
- function getRowUserFromPoint(x: number, y: number): string | null {
132
- const el = document.elementFromPoint(x, y);
133
- if (!el) return null;
134
- const row = el.closest(".gantt-row") as HTMLElement | null;
135
- if (!row) return null;
142
+ function getRowInfoFromPoint(x: number, y: number): { user: string; daysEl: HTMLElement | null } {
143
+ const el = document.elementFromPoint(x, y) as HTMLElement | null;
144
+ const row = el?.closest(".gantt-row") as HTMLElement | null;
145
+ if (!row) return { user: "", daysEl: null };
136
146
 
137
147
  const label = row.querySelector(".task-column-label")?.textContent?.trim();
138
- return label && label !== "Unassigned" ? label : "";
148
+ const user = label && label !== "Unassigned" ? label : ""; // empty string is our Unassigned key
149
+ const daysEl = row.querySelector(".days") as HTMLElement | null;
150
+ return { user, daysEl };
139
151
  }
140
152
 
141
153
  const onPointerDownBar = (
@@ -143,6 +155,7 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
143
155
  taskId: string,
144
156
  mode: "move" | "resize-start" | "resize-end"
145
157
  ) => {
158
+ e.preventDefault();
146
159
  const task = tasks.find((t) => t.id === taskId);
147
160
  if (!task) return;
148
161
 
@@ -158,22 +171,24 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
158
171
  originX: e.clientX,
159
172
  originLeftMin: dateToMinuteIndex(startDate, taskStart),
160
173
  originRightMin: dateToMinuteIndex(startDate, taskEnd),
161
- originUser: task.user ?? ""
174
+ originUser: task.user ?? "",
162
175
  };
163
176
 
164
177
  if (mode === "move") {
165
- setDragGhost({ taskId, x: e.clientX, y: e.clientY });
178
+ setDragGhost({ taskId, x: e.clientX, y: e.clientY, rowUser: task.user ?? "" });
166
179
  }
167
180
 
168
181
  const onPointerMove = (ev: PointerEvent) => {
169
182
  if (!dragState.current) return;
183
+ if (minuteWidth <= 0) return;
170
184
  const ds = dragState.current;
171
185
  const dx = ev.clientX - ds.originX;
172
186
  const deltaMinutes = Math.round(pxToMinutes(dx));
173
187
 
174
188
  if (ds.mode === "move") {
189
+ const { user: hoverUser } = getRowInfoFromPoint(ev.clientX, ev.clientY);
175
190
  setDragGhost((ghost) =>
176
- ghost ? { ...ghost, x: ev.clientX, y: ev.clientY } : null
191
+ ghost ? { ...ghost, x: ev.clientX, y: ev.clientY, rowUser: hoverUser } : null
177
192
  );
178
193
  }
179
194
 
@@ -189,25 +204,19 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
189
204
  return {
190
205
  ...t,
191
206
  start: formatISO(newStart, { representation: "complete" }),
192
- end: formatISO(newEnd, { representation: "complete" })
207
+ end: formatISO(newEnd, { representation: "complete" }),
193
208
  };
194
209
  }
195
210
 
196
211
  if (ds.mode === "resize-start") {
197
212
  const newLeft = clamp(ds.originLeftMin + deltaMinutes, 0, ds.originRightMin - 1);
198
213
  const newStart = addMinutes(startDate, newLeft);
199
- return {
200
- ...t,
201
- start: formatISO(newStart, { representation: "complete" })
202
- };
214
+ return { ...t, start: formatISO(newStart, { representation: "complete" }) };
203
215
  }
204
216
 
205
217
  const newRight = clamp(ds.originRightMin + deltaMinutes, ds.originLeftMin + 1, totalDays * 24 * 60);
206
218
  const newEnd = addMinutes(startDate, newRight);
207
- return {
208
- ...t,
209
- end: formatISO(newEnd, { representation: "complete" })
210
- };
219
+ return { ...t, end: formatISO(newEnd, { representation: "complete" }) };
211
220
  })
212
221
  );
213
222
  };
@@ -217,48 +226,38 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
217
226
  target.releasePointerCapture(e.pointerId);
218
227
  } catch {}
219
228
 
220
- const dropUser = dragGhost
221
- ? getRowUserFromPoint(dragGhost.x, dragGhost.y)
222
- : getRowUserFromPoint(ev.clientX, ev.clientY);
223
-
224
- if (dragState.current) {
225
- const ds = dragState.current;
226
-
227
- // find position in minutes relative to chart
228
- const daysEl = daysRef.current;
229
- if (daysEl) {
230
- const rect = daysEl.getBoundingClientRect();
231
- const dropX = (dragGhost?.x ?? ev.clientX) - rect.left;
232
- const dropMinutes = Math.round(pxToMinutes(dropX));
233
-
234
- setTasks((prev) =>
235
- prev.map((t) => {
236
- if (t.id !== ds.taskId) return t;
237
-
238
- const duration = minutesBetween(new Date(t.start), new Date(t.end));
239
- const newStart = addMinutes(startDate, clamp(dropMinutes, 0, 24 * 60 - duration));
240
- const newEnd = addMinutes(newStart, duration);
241
-
242
- return {
243
- ...t,
244
- start: formatISO(newStart, { representation: "complete" }),
245
- end: formatISO(newEnd, { representation: "complete" }),
246
- user: dropUser ?? t.user,
247
- };
248
- })
249
- );
250
- }
229
+ const { user: dropUser, daysEl } = dragGhost
230
+ ? getRowInfoFromPoint(dragGhost.x, dragGhost.y)
231
+ : getRowInfoFromPoint(ev.clientX, ev.clientY);
232
+
233
+ const ds = dragState.current;
234
+ if (ds && daysEl) {
235
+ const rect = daysEl.getBoundingClientRect();
236
+ const dropX = (dragGhost?.x ?? ev.clientX) - rect.left;
237
+ const dropMinutes = Math.round(pxToMinutes(dropX));
238
+
239
+ setTasks((prev) => {
240
+ return prev.map((t) => {
241
+ if (t.id !== ds.taskId) return t;
242
+ const duration = minutesBetween(new Date(t.start), new Date(t.end));
243
+ const newStart = addMinutes(startDate, clamp(dropMinutes, 0, 24 * 60 - duration));
244
+ const newEnd = addMinutes(newStart, duration);
245
+ return {
246
+ ...t,
247
+ start: formatISO(newStart, { representation: "complete" }),
248
+ end: formatISO(newEnd, { representation: "complete" }),
249
+ user: dropUser ?? t.user,
250
+ };
251
+ });
252
+ });
251
253
  }
252
254
 
253
255
  setDragGhost(null);
254
256
  dragState.current = null;
255
257
  window.removeEventListener("pointermove", onPointerMove);
256
258
  window.removeEventListener("pointerup", onPointerUp);
257
-
258
- if (onChange) onChange(tasks);
259
259
  };
260
260
 
261
-
262
261
  window.addEventListener("pointermove", onPointerMove);
263
262
  window.addEventListener("pointerup", onPointerUp);
264
263
  };
@@ -270,7 +269,6 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
270
269
  const dayStart = startOfDay(currentDay);
271
270
  const dayEnd = addMinutes(dayStart, 24 * 60);
272
271
 
273
- // Clip task to current day
274
272
  const displayStart = taskStart < dayStart ? dayStart : taskStart;
275
273
  const displayEnd = taskEnd > dayEnd ? dayEnd : taskEnd;
276
274
 
@@ -289,23 +287,17 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
289
287
  left: leftPx,
290
288
  width: widthPx,
291
289
  backgroundColor: task.color,
292
- opacity: dragGhost?.taskId === task.id ? 0.4 : 1
290
+ opacity: dragGhost?.taskId === task.id ? 0.4 : 1,
293
291
  }}
294
292
  >
295
- {/*<div*/}
296
- {/* className="resize-handle left"*/}
297
- {/* onPointerDown={(e) => onPointerDownBar(e, task.id, "resize-start")}*/}
298
- {/*/>*/}
299
- <div className="bar" >
300
- <div onPointerDown={(e) => onPointerDownBar(e, task.id, "move")} className={'bar-drag'}>
301
- <DotsSixVertical/>
293
+ {/* <div className="resize-handle left" onPointerDown={(e) => onPointerDownBar(e, task.id, "resize-start")} /> */}
294
+ <div className="bar">
295
+ <div onPointerDown={(e) => onPointerDownBar(e, task.id, "move")} className={"bar-drag"}>
296
+ <DotsSixVertical />
302
297
  </div>
303
298
  <span>{task.name}</span>
304
299
  </div>
305
- {/*<div*/}
306
- {/* className="resize-handle right"*/}
307
- {/* onPointerDown={(e) => onPointerDownBar(e, task.id, "resize-end")}*/}
308
- {/*/>*/}
300
+ {/* <div className="resize-handle right" onPointerDown={(e) => onPointerDownBar(e, task.id, "resize-end")} /> */}
309
301
  </div>
310
302
  );
311
303
  };
@@ -324,7 +316,7 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
324
316
  <div className="days">
325
317
  <div className="date-day-view current-day">
326
318
  <div className="single-date">{format(currentDay, "MM/dd")}</div>
327
- <div className="hours">
319
+ <div className="hours" ref={headerHoursRef}>
328
320
  {Array.from({ length: 24 }).map((_, h) => (
329
321
  <div className="hour" key={h}>
330
322
  {`${String(h).padStart(2, "0")}:00`}
@@ -344,10 +336,8 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
344
336
  })
345
337
  .map((task) => (
346
338
  <div key={task.id} className="gantt-row">
347
- <div className="task-column-label">
348
- {task.user?.trim() || "Unassigned"}
349
- </div>
350
- <div className="days" ref={daysRef}>
339
+ <div className="task-column-label">{task.user?.trim() || "Unassigned"}</div>
340
+ <div className="days">
351
341
  {timeUnits.map((d) => (
352
342
  <div date-cell={d.toISOString()} key={d.toISOString()} />
353
343
  ))}
@@ -358,7 +348,6 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
358
348
  </div>
359
349
  </div>
360
350
 
361
- {/* Floating drag ghost */}
362
351
  {dragGhost && (
363
352
  <div
364
353
  className="drag-ghost"
@@ -368,17 +357,15 @@ export default function GanttChart({ tasks: initialTasks, onChange }: GanttChart
368
357
  top: dragGhost.y,
369
358
  pointerEvents: "none",
370
359
  opacity: 0.8,
371
- background: tasks.find(t => t.id === dragGhost.taskId)?.color ?? "gray",
360
+ background: tasks.find((t) => t.id === dragGhost.taskId)?.color ?? "gray",
372
361
  padding: "0px 6px",
373
- height:'24px',
374
- width: '100px',
362
+ height: "24px",
363
+ width: "100px",
375
364
  borderRadius: 4,
376
- zIndex: 9999
365
+ zIndex: 9999,
377
366
  }}
378
367
  >
379
- <span>
380
- {tasks.find(t => t.id === dragGhost.taskId)?.name}
381
- </span>
368
+ <span>{tasks.find((t) => t.id === dragGhost.taskId)?.name}</span>
382
369
  </div>
383
370
  )}
384
371
  </>
@@ -0,0 +1,47 @@
1
+ import IconProps from "../../IconProps";
2
+
3
+ const Folders = ({type = "light"}: IconProps) => {
4
+ if (type === "thin") {
5
+ return (
6
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
7
+ <path d="M28 8.5H19.3337C19.2256 8.5 19.1203 8.46491 19.0338 8.4L15.5662 5.8C15.3064 5.60567 14.9907 5.50045 14.6663 5.5H9C8.60218 5.5 8.22064 5.65804 7.93934 5.93934C7.65804 6.22064 7.5 6.60218 7.5 7V9.5H5C4.60218 9.5 4.22064 9.65804 3.93934 9.93934C3.65804 10.2206 3.5 10.6022 3.5 11V25C3.5 25.3978 3.65804 25.7794 3.93934 26.0607C4.22064 26.342 4.60218 26.5 5 26.5H24.1112C24.4795 26.4997 24.8325 26.3532 25.0929 26.0929C25.3532 25.8325 25.4997 25.4795 25.5 25.1112V22.5H28.1112C28.4795 22.4997 28.8325 22.3532 29.0929 22.0929C29.3532 21.8325 29.4997 21.4795 29.5 21.1112V10C29.5 9.60218 29.342 9.22064 29.0607 8.93934C28.7794 8.65804 28.3978 8.5 28 8.5ZM24.5 25.1112C24.4997 25.2143 24.4586 25.3129 24.3858 25.3858C24.3129 25.4586 24.2143 25.4997 24.1112 25.5H5C4.86739 25.5 4.74021 25.4473 4.64645 25.3536C4.55268 25.2598 4.5 25.1326 4.5 25V11C4.5 10.8674 4.55268 10.7402 4.64645 10.6464C4.74021 10.5527 4.86739 10.5 5 10.5H10.6663C10.7744 10.5 10.8797 10.5351 10.9663 10.6L14.4338 13.2C14.6936 13.3943 15.0093 13.4996 15.3337 13.5H24C24.1326 13.5 24.2598 13.5527 24.3536 13.6464C24.4473 13.7402 24.5 13.8674 24.5 14V25.1112ZM28.5 21.1112C28.4997 21.2143 28.4586 21.3129 28.3858 21.3858C28.3129 21.4586 28.2143 21.4997 28.1112 21.5H25.5V14C25.5 13.6022 25.342 13.2206 25.0607 12.9393C24.7794 12.658 24.3978 12.5 24 12.5H15.3337C15.2256 12.5 15.1203 12.4649 15.0337 12.4L11.5662 9.8C11.3064 9.60567 10.9907 9.50045 10.6663 9.5H8.5V7C8.5 6.86739 8.55268 6.74021 8.64645 6.64645C8.74021 6.55268 8.86739 6.5 9 6.5H14.6663C14.7744 6.5 14.8797 6.53509 14.9663 6.6L18.4338 9.2C18.6936 9.39433 19.0093 9.49955 19.3337 9.5H28C28.1326 9.5 28.2598 9.55268 28.3536 9.64645C28.4473 9.74021 28.5 9.86739 28.5 10V21.1112Z" fill="currrentColor"/>
8
+ </svg>
9
+ );
10
+ }
11
+ if (type === "regular") {
12
+ return (
13
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
14
+ <path d="M28 8H19.3337L15.8663 5.4C15.5196 5.14132 15.0988 5.00107 14.6663 5H9C8.46957 5 7.96086 5.21071 7.58579 5.58579C7.21071 5.96086 7 6.46957 7 7V9H5C4.46957 9 3.96086 9.21071 3.58579 9.58579C3.21071 9.96086 3 10.4696 3 11V25C3 25.5304 3.21071 26.0391 3.58579 26.4142C3.96086 26.7893 4.46957 27 5 27H24.1112C24.612 26.9993 25.092 26.8001 25.4461 26.4461C25.8001 26.092 25.9993 25.612 26 25.1112V23H28.1112C28.612 22.9993 29.092 22.8001 29.4461 22.4461C29.8001 22.092 29.9993 21.612 30 21.1112V10C30 9.46957 29.7893 8.96086 29.4142 8.58579C29.0391 8.21071 28.5304 8 28 8ZM24 25H5V11H10.6663L14.1337 13.6C14.4804 13.8587 14.9012 13.9989 15.3337 14H24V25ZM28 21H26V14C26 13.4696 25.7893 12.9609 25.4142 12.5858C25.0391 12.2107 24.5304 12 24 12H15.3337L11.8663 9.4C11.5196 9.14132 11.0988 9.00107 10.6663 9H9V7H14.6663L18.1338 9.6C18.4804 9.85868 18.9012 9.99893 19.3337 10H28V21Z" fill="currrentColor"/>
15
+ </svg>
16
+ );
17
+ }
18
+ if (type === "bold") {
19
+ return (
20
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
21
+ <path d="M28.5 7H20L16.6663 4.5C16.233 4.17641 15.707 4.00107 15.1663 4H9.5C8.83696 4 8.20107 4.26339 7.73223 4.73223C7.26339 5.20107 7 5.83696 7 6.5V9H4.5C3.83696 9 3.20107 9.26339 2.73223 9.73223C2.26339 10.2011 2 10.837 2 11.5V25.5C2 26.163 2.26339 26.7989 2.73223 27.2678C3.20107 27.7366 3.83696 28 4.5 28H23.6112C24.2446 27.9993 24.8518 27.7475 25.2996 27.2996C25.7475 26.8518 25.9993 26.2446 26 25.6112V23H28.6112C29.2446 22.9993 29.8518 22.7475 30.2996 22.2996C30.7475 21.8518 30.9993 21.2446 31 20.6112V9.5C31 8.83696 30.7366 8.20107 30.2678 7.73223C29.7989 7.26339 29.163 7 28.5 7ZM23 25H5V12H10L13.3337 14.5C13.767 14.8236 14.293 14.9989 14.8337 15H23V25ZM28 20H26V14.5C26 13.837 25.7366 13.2011 25.2678 12.7322C24.7989 12.2634 24.163 12 23.5 12H15L11.6663 9.5C11.233 9.17641 10.707 9.00107 10.1663 9H10V7H15L18.3337 9.5C18.767 9.82359 19.293 9.99893 19.8337 10H28V20Z" fill="currrentColor"/>
22
+ </svg>
23
+ );
24
+ }
25
+ if (type === "fill") {
26
+ return (
27
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
28
+ <path d="M28 8H19.3337L15.8663 5.4C15.5196 5.14132 15.0988 5.00107 14.6663 5H9C8.46957 5 7.96086 5.21071 7.58579 5.58579C7.21071 5.96086 7 6.46957 7 7V9H5C4.46957 9 3.96086 9.21071 3.58579 9.58579C3.21071 9.96086 3 10.4696 3 11V25C3 25.5304 3.21071 26.0391 3.58579 26.4142C3.96086 26.7893 4.46957 27 5 27H24.1112C24.612 26.9993 25.092 26.8001 25.4461 26.4461C25.8001 26.092 25.9993 25.612 26 25.1112V23H28.1112C28.612 22.9993 29.092 22.8001 29.4461 22.4461C29.8001 22.092 29.9993 21.612 30 21.1112V10C30 9.46957 29.7893 8.96086 29.4142 8.58579C29.0391 8.21071 28.5304 8 28 8ZM28 21H26V14C26 13.4696 25.7893 12.9609 25.4142 12.5858C25.0391 12.2107 24.5304 12 24 12H15.3337L11.8663 9.4C11.5196 9.14132 11.0988 9.00107 10.6663 9H9V7H14.6663L18.1338 9.6C18.4804 9.85868 18.9012 9.99893 19.3337 10H28V21Z" fill="currrentColor"/>
29
+ </svg>
30
+ );
31
+ }
32
+ if (type === "duotone") {
33
+ return (
34
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
35
+ <path opacity="0.2" d="M29 10V21.1112C29 21.347 28.9064 21.573 28.7397 21.7397C28.573 21.9064 28.347 22 28.1112 22H25V14C25 13.7348 24.8946 13.4804 24.7071 13.2929C24.5196 13.1054 24.2652 13 24 13H15.3337C15.1174 13 14.9068 12.9298 14.7338 12.8L11.2662 10.2C11.0932 10.0702 10.8826 10 10.6663 10H8V7C8 6.73478 8.10536 6.48043 8.29289 6.29289C8.48043 6.10536 8.73478 6 9 6H14.6663C14.8826 6 15.0932 6.07018 15.2662 6.2L18.7337 8.8C18.9068 8.92982 19.1174 9 19.3337 9H28C28.2652 9 28.5196 9.10536 28.7071 9.29289C28.8946 9.48043 29 9.73478 29 10Z" fill="currrentColor"/>
36
+ <path d="M28 8H19.3337L15.8663 5.4C15.5196 5.14132 15.0988 5.00107 14.6663 5H9C8.46957 5 7.96086 5.21071 7.58579 5.58579C7.21071 5.96086 7 6.46957 7 7V9H5C4.46957 9 3.96086 9.21071 3.58579 9.58579C3.21071 9.96086 3 10.4696 3 11V25C3 25.5304 3.21071 26.0391 3.58579 26.4142C3.96086 26.7893 4.46957 27 5 27H24.1112C24.612 26.9993 25.092 26.8001 25.4461 26.4461C25.8001 26.092 25.9993 25.612 26 25.1112V23H28.1112C28.612 22.9993 29.092 22.8001 29.4461 22.4461C29.8001 22.092 29.9993 21.612 30 21.1112V10C30 9.46957 29.7893 8.96086 29.4142 8.58579C29.0391 8.21071 28.5304 8 28 8ZM24 25H5V11H10.6663L14.1337 13.6C14.4804 13.8587 14.9012 13.9989 15.3337 14H24V25ZM28 21H26V14C26 13.4696 25.7893 12.9609 25.4142 12.5858C25.0391 12.2107 24.5304 12 24 12H15.3337L11.8663 9.4C11.5196 9.14132 11.0988 9.00107 10.6663 9H9V7H14.6663L18.1338 9.6C18.4804 9.85868 18.9012 9.99893 19.3337 10H28V21Z" fill="currrentColor"/>
37
+ </svg>
38
+ );
39
+ }
40
+ return (
41
+ <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
42
+ <path d="M28 8.25H19.3337C19.2797 8.25 19.227 8.23246 19.1838 8.2L15.7163 5.6C15.4133 5.37281 15.0449 5.25 14.6663 5.25H9C8.53587 5.25 8.09075 5.43437 7.76256 5.76256C7.43437 6.09075 7.25 6.53587 7.25 7V9.25H5C4.53587 9.25 4.09075 9.43437 3.76256 9.76256C3.43437 10.0908 3.25 10.5359 3.25 11V25C3.25 25.4641 3.43437 25.9092 3.76256 26.2374C4.09075 26.5656 4.53587 26.75 5 26.75H24.1112C24.5458 26.7497 24.9624 26.5769 25.2697 26.2697C25.5769 25.9624 25.7497 25.5458 25.75 25.1112V22.75H28.1112C28.5458 22.7497 28.9624 22.5769 29.2697 22.2697C29.5769 21.9624 29.7497 21.5458 29.75 21.1112V10C29.75 9.53587 29.5656 9.09075 29.2374 8.76256C28.9092 8.43437 28.4641 8.25 28 8.25ZM24.25 25.1112C24.25 25.148 24.2354 25.1833 24.2094 25.2094C24.1833 25.2354 24.148 25.25 24.1112 25.25H5C4.9337 25.25 4.87011 25.2237 4.82322 25.1768C4.77634 25.1299 4.75 25.0663 4.75 25V11C4.75 10.9337 4.77634 10.8701 4.82322 10.8232C4.87011 10.7763 4.9337 10.75 5 10.75H10.6663C10.7203 10.75 10.773 10.7675 10.8162 10.8L14.2837 13.4C14.5867 13.6272 14.9551 13.75 15.3337 13.75H24C24.0663 13.75 24.1299 13.7763 24.1768 13.8232C24.2237 13.8701 24.25 13.9337 24.25 14V25.1112ZM28.25 21.1112C28.25 21.1295 28.2464 21.1475 28.2394 21.1643C28.2325 21.1812 28.2222 21.1965 28.2094 21.2094C28.1965 21.2222 28.1812 21.2325 28.1643 21.2394C28.1475 21.2464 28.1295 21.25 28.1112 21.25H25.75V14C25.75 13.5359 25.5656 13.0908 25.2374 12.7626C24.9092 12.4344 24.4641 12.25 24 12.25H15.3337C15.2797 12.25 15.227 12.2325 15.1838 12.2L11.7163 9.6C11.4133 9.37281 11.0449 9.25 10.6663 9.25H8.75V7C8.75 6.9337 8.77634 6.87011 8.82322 6.82322C8.87011 6.77634 8.9337 6.75 9 6.75H14.6663C14.7203 6.75 14.773 6.76754 14.8162 6.8L18.2838 9.4C18.5867 9.62719 18.9551 9.75 19.3337 9.75H28C28.0663 9.75 28.1299 9.77634 28.1768 9.82322C28.2237 9.87011 28.25 9.9337 28.25 10V21.1112Z" fill="currrentColor"/>
43
+ </svg>
44
+ );
45
+ };
46
+
47
+ export default Folders;
@@ -84,6 +84,7 @@ export { default as VideoCamera } from './Media/VideoCamera/VideoCamera.tsx';
84
84
  export { default as TextAa } from './OfficeAndEditing/TextAa/TextAa.tsx';
85
85
  export { default as TextColumns } from './OfficeAndEditing/TextColumns/TextColumns.tsx';
86
86
  export { default as Folder } from './OfficeAndEditing/Folder/Folder.tsx';
87
+ export { default as Folders } from './OfficeAndEditing/Folders/Folders.tsx';
87
88
  export { default as ListBullets } from './OfficeAndEditing/ListBullets/ListBullets.tsx';
88
89
  export { default as List } from './OfficeAndEditing/List/List.tsx';
89
90
  export { default as ListDashes } from './OfficeAndEditing/ListDashes/ListDashes.tsx';