@almadar/ui 4.50.5 → 4.50.6

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.
@@ -21138,10 +21138,18 @@ function useDataDnd(args) {
21138
21138
  const target = isRoot ? null : parentRoot;
21139
21139
  if (!target) {
21140
21140
  zonesRef.current.set(zoneId, meta);
21141
- return () => zonesRef.current.delete(zoneId);
21141
+ dndLog.debug("zone:register:self", { zoneId, group: meta.group, itemCount: meta.itemIds.length, isRoot });
21142
+ return () => {
21143
+ zonesRef.current.delete(zoneId);
21144
+ dndLog.debug("zone:unregister:self", { zoneId, group: meta.group });
21145
+ };
21142
21146
  }
21143
21147
  target.registerZone(zoneId, meta);
21144
- return () => target.unregisterZone(zoneId);
21148
+ dndLog.debug("zone:register", { zoneId, group: meta.group, itemCount: meta.itemIds.length, dropEvent: meta.dropEvent, reorderEvent: meta.reorderEvent });
21149
+ return () => {
21150
+ target.unregisterZone(zoneId);
21151
+ dndLog.debug("zone:unregister", { zoneId, group: meta.group });
21152
+ };
21145
21153
  }, [parentRoot, isRoot, zoneId, meta]);
21146
21154
  const sensors = core$1.useSensors(
21147
21155
  core$1.useSensor(core$1.PointerSensor, { activationConstraint: { distance: 5 } }),
@@ -21149,10 +21157,18 @@ function useDataDnd(args) {
21149
21157
  );
21150
21158
  const collisionDetection = React80__namespace.default.useCallback((args2) => {
21151
21159
  const pointerCollisions = core$1.pointerWithin(args2);
21152
- if (pointerCollisions.length > 0) return pointerCollisions;
21160
+ if (pointerCollisions.length > 0) {
21161
+ dndLog.debug("collision:pointerWithin", { count: pointerCollisions.length, ids: pointerCollisions.map((c) => c.id) });
21162
+ return pointerCollisions;
21163
+ }
21153
21164
  const rectCollisions = core$1.rectIntersection(args2);
21154
- if (rectCollisions.length > 0) return rectCollisions;
21155
- return core$1.closestCorners(args2);
21165
+ if (rectCollisions.length > 0) {
21166
+ dndLog.debug("collision:rectIntersection", { count: rectCollisions.length, ids: rectCollisions.map((c) => c.id) });
21167
+ return rectCollisions;
21168
+ }
21169
+ const cornerCollisions = core$1.closestCorners(args2);
21170
+ dndLog.debug("collision:closestCorners", { count: cornerCollisions.length, ids: cornerCollisions.map((c) => c.id) });
21171
+ return cornerCollisions;
21156
21172
  }, []);
21157
21173
  const findZoneByItem = React80__namespace.default.useCallback(
21158
21174
  (id) => {
@@ -21175,22 +21191,52 @@ function useDataDnd(args) {
21175
21191
  const handleDragEnd = React80__namespace.default.useCallback(
21176
21192
  (event) => {
21177
21193
  const { active, over } = event;
21178
- if (!over) return;
21194
+ const allZones = Array.from(zonesRef.current.entries()).map(([id, m]) => ({ id, group: m.group, items: m.itemIds.length }));
21195
+ dndLog.debug("dragEnd:received", {
21196
+ activeId: active.id,
21197
+ overId: over?.id,
21198
+ overData: over?.data?.current,
21199
+ zones: allZones
21200
+ });
21201
+ if (!over) {
21202
+ dndLog.warn("dragEnd:abort:no-over", { activeId: active.id, reason: "no droppable under pointer at drop time \u2192 item snaps back" });
21203
+ return;
21204
+ }
21179
21205
  const sourceZone = findZoneByItem(active.id);
21180
21206
  const overData = over.data?.current;
21181
21207
  const targetGroup = overData?.dndGroup;
21182
- if (!sourceZone || !targetGroup) return;
21208
+ dndLog.debug("dragEnd:resolved", { sourceGroup: sourceZone?.group, targetGroup, overDataKeys: overData ? Object.keys(overData) : null });
21209
+ if (!sourceZone) {
21210
+ dndLog.warn("dragEnd:abort:no-source-zone", { activeId: active.id });
21211
+ return;
21212
+ }
21213
+ if (!targetGroup) {
21214
+ dndLog.warn("dragEnd:abort:no-target-group", { overId: over.id, overData });
21215
+ return;
21216
+ }
21183
21217
  const targetZone = findZoneByGroup(targetGroup);
21184
- if (!targetZone) return;
21218
+ if (!targetZone) {
21219
+ dndLog.warn("dragEnd:abort:target-zone-not-registered", { targetGroup });
21220
+ return;
21221
+ }
21185
21222
  if (sourceZone.group !== targetZone.group) {
21186
21223
  if (targetZone.dropEvent) {
21187
21224
  const newIndex2 = targetZone.itemIds.indexOf(over.id);
21225
+ dndLog.info("dragEnd:cross-container:emit", {
21226
+ event: targetZone.dropEvent,
21227
+ id: String(active.id),
21228
+ sourceGroup: sourceZone.group,
21229
+ targetGroup: targetZone.group,
21230
+ newIndex: newIndex2 === -1 ? targetZone.itemIds.length : newIndex2
21231
+ });
21188
21232
  eventBus.emit(targetZone.dropEvent, {
21189
21233
  id: String(active.id),
21190
21234
  sourceGroup: sourceZone.group,
21191
21235
  targetGroup: targetZone.group,
21192
21236
  newIndex: newIndex2 === -1 ? targetZone.itemIds.length : newIndex2
21193
21237
  });
21238
+ } else {
21239
+ dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetZone.group });
21194
21240
  }
21195
21241
  return;
21196
21242
  }
@@ -21202,11 +21248,19 @@ function useDataDnd(args) {
21202
21248
  setLocalOrder(reordered);
21203
21249
  }
21204
21250
  if (sourceZone.reorderEvent) {
21251
+ dndLog.info("dragEnd:reorder:emit", {
21252
+ event: sourceZone.reorderEvent,
21253
+ id: String(active.id),
21254
+ oldIndex,
21255
+ newIndex
21256
+ });
21205
21257
  eventBus.emit(sourceZone.reorderEvent, {
21206
21258
  id: String(active.id),
21207
21259
  oldIndex,
21208
21260
  newIndex
21209
21261
  });
21262
+ } else {
21263
+ dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceZone.group });
21210
21264
  }
21211
21265
  },
21212
21266
  [orderedItems, ownGroup, findZoneByItem, findZoneByGroup, eventBus]
@@ -21247,15 +21301,20 @@ function useDataDnd(args) {
21247
21301
  [sortableData, enabled]
21248
21302
  );
21249
21303
  const DropZoneShell = ({ children }) => {
21304
+ const droppableId = `dnd-zone-${zoneId}`;
21250
21305
  const { setNodeRef, isOver } = core$1.useDroppable({
21251
- id: `dnd-zone-${zoneId}`,
21306
+ id: droppableId,
21252
21307
  data: sortableData
21253
21308
  });
21309
+ React80__namespace.default.useEffect(() => {
21310
+ dndLog.debug("dropzone:isOver:change", { droppableId, group: ownGroup, isOver });
21311
+ }, [droppableId, isOver]);
21254
21312
  return /* @__PURE__ */ jsxRuntime.jsx(
21255
21313
  Box,
21256
21314
  {
21257
21315
  ref: setNodeRef,
21258
21316
  "data-dnd-zone": ownGroup,
21317
+ "data-dnd-is-over": isOver ? "true" : "false",
21259
21318
  className: isOver ? "ring-2 ring-primary ring-offset-2 rounded-lg transition-all min-h-[3rem]" : "min-h-[3rem] rounded-lg transition-all",
21260
21319
  children
21261
21320
  }
@@ -21265,21 +21324,65 @@ function useDataDnd(args) {
21265
21324
  () => ({ registerZone, unregisterZone }),
21266
21325
  [registerZone, unregisterZone]
21267
21326
  );
21327
+ const handleDragStart = React80__namespace.default.useCallback((event) => {
21328
+ const sourceZone = findZoneByItem(event.active.id);
21329
+ dndLog.info("dragStart", {
21330
+ activeId: event.active.id,
21331
+ activeData: event.active.data?.current,
21332
+ sourceGroup: sourceZone?.group,
21333
+ zoneCount: zonesRef.current.size
21334
+ });
21335
+ }, [findZoneByItem]);
21336
+ const handleDragOver = React80__namespace.default.useCallback((event) => {
21337
+ dndLog.debug("dragOver", {
21338
+ activeId: event.active.id,
21339
+ overId: event.over?.id,
21340
+ overData: event.over?.data?.current
21341
+ });
21342
+ }, []);
21343
+ const handleDragCancel = React80__namespace.default.useCallback((event) => {
21344
+ dndLog.warn("dragCancel", {
21345
+ activeId: event.active.id,
21346
+ reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
21347
+ });
21348
+ }, []);
21268
21349
  const wrapContainer = React80__namespace.default.useCallback(
21269
21350
  (children) => {
21270
21351
  if (!enabled) return children;
21271
21352
  const strategy = layout === "grid" ? sortable.rectSortingStrategy : sortable.verticalListSortingStrategy;
21272
21353
  if (!isZone) {
21273
21354
  if (!isRoot) return children;
21274
- return /* @__PURE__ */ jsxRuntime.jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(core$1.DndContext, { sensors, collisionDetection, onDragEnd: handleDragEnd, children }) });
21355
+ return /* @__PURE__ */ jsxRuntime.jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
21356
+ core$1.DndContext,
21357
+ {
21358
+ sensors,
21359
+ collisionDetection,
21360
+ onDragStart: handleDragStart,
21361
+ onDragOver: handleDragOver,
21362
+ onDragEnd: handleDragEnd,
21363
+ onDragCancel: handleDragCancel,
21364
+ children
21365
+ }
21366
+ ) });
21275
21367
  }
21276
21368
  const inner = /* @__PURE__ */ jsxRuntime.jsx(DropZoneShell, { children: /* @__PURE__ */ jsxRuntime.jsx(sortable.SortableContext, { items: itemIds, strategy, children }) });
21277
21369
  if (isRoot) {
21278
- return /* @__PURE__ */ jsxRuntime.jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(core$1.DndContext, { sensors, collisionDetection, onDragEnd: handleDragEnd, children: inner }) });
21370
+ return /* @__PURE__ */ jsxRuntime.jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
21371
+ core$1.DndContext,
21372
+ {
21373
+ sensors,
21374
+ collisionDetection,
21375
+ onDragStart: handleDragStart,
21376
+ onDragOver: handleDragOver,
21377
+ onDragEnd: handleDragEnd,
21378
+ onDragCancel: handleDragCancel,
21379
+ children: inner
21380
+ }
21381
+ ) });
21279
21382
  }
21280
21383
  return inner;
21281
21384
  },
21282
- [enabled, isZone, layout, sensors, collisionDetection, handleDragEnd, itemIds, isRoot, rootContextValue]
21385
+ [enabled, isZone, layout, sensors, collisionDetection, handleDragStart, handleDragOver, handleDragEnd, handleDragCancel, itemIds, isRoot, rootContextValue]
21283
21386
  );
21284
21387
  return {
21285
21388
  enabled,
@@ -21289,12 +21392,13 @@ function useDataDnd(args) {
21289
21392
  orderedItems
21290
21393
  };
21291
21394
  }
21292
- var RootCtx;
21395
+ var dndLog, RootCtx;
21293
21396
  var init_useDataDnd = __esm({
21294
21397
  "components/molecules/useDataDnd.tsx"() {
21295
21398
  "use client";
21296
21399
  init_useEventBus();
21297
21400
  init_Box();
21401
+ dndLog = logger.createLogger("almadar:ui:dnd");
21298
21402
  RootCtx = React80__namespace.default.createContext(null);
21299
21403
  }
21300
21404
  });
@@ -21092,10 +21092,18 @@ function useDataDnd(args) {
21092
21092
  const target = isRoot ? null : parentRoot;
21093
21093
  if (!target) {
21094
21094
  zonesRef.current.set(zoneId, meta);
21095
- return () => zonesRef.current.delete(zoneId);
21095
+ dndLog.debug("zone:register:self", { zoneId, group: meta.group, itemCount: meta.itemIds.length, isRoot });
21096
+ return () => {
21097
+ zonesRef.current.delete(zoneId);
21098
+ dndLog.debug("zone:unregister:self", { zoneId, group: meta.group });
21099
+ };
21096
21100
  }
21097
21101
  target.registerZone(zoneId, meta);
21098
- return () => target.unregisterZone(zoneId);
21102
+ dndLog.debug("zone:register", { zoneId, group: meta.group, itemCount: meta.itemIds.length, dropEvent: meta.dropEvent, reorderEvent: meta.reorderEvent });
21103
+ return () => {
21104
+ target.unregisterZone(zoneId);
21105
+ dndLog.debug("zone:unregister", { zoneId, group: meta.group });
21106
+ };
21099
21107
  }, [parentRoot, isRoot, zoneId, meta]);
21100
21108
  const sensors = useSensors(
21101
21109
  useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
@@ -21103,10 +21111,18 @@ function useDataDnd(args) {
21103
21111
  );
21104
21112
  const collisionDetection = React80__default.useCallback((args2) => {
21105
21113
  const pointerCollisions = pointerWithin(args2);
21106
- if (pointerCollisions.length > 0) return pointerCollisions;
21114
+ if (pointerCollisions.length > 0) {
21115
+ dndLog.debug("collision:pointerWithin", { count: pointerCollisions.length, ids: pointerCollisions.map((c) => c.id) });
21116
+ return pointerCollisions;
21117
+ }
21107
21118
  const rectCollisions = rectIntersection(args2);
21108
- if (rectCollisions.length > 0) return rectCollisions;
21109
- return closestCorners(args2);
21119
+ if (rectCollisions.length > 0) {
21120
+ dndLog.debug("collision:rectIntersection", { count: rectCollisions.length, ids: rectCollisions.map((c) => c.id) });
21121
+ return rectCollisions;
21122
+ }
21123
+ const cornerCollisions = closestCorners(args2);
21124
+ dndLog.debug("collision:closestCorners", { count: cornerCollisions.length, ids: cornerCollisions.map((c) => c.id) });
21125
+ return cornerCollisions;
21110
21126
  }, []);
21111
21127
  const findZoneByItem = React80__default.useCallback(
21112
21128
  (id) => {
@@ -21129,22 +21145,52 @@ function useDataDnd(args) {
21129
21145
  const handleDragEnd = React80__default.useCallback(
21130
21146
  (event) => {
21131
21147
  const { active, over } = event;
21132
- if (!over) return;
21148
+ const allZones = Array.from(zonesRef.current.entries()).map(([id, m]) => ({ id, group: m.group, items: m.itemIds.length }));
21149
+ dndLog.debug("dragEnd:received", {
21150
+ activeId: active.id,
21151
+ overId: over?.id,
21152
+ overData: over?.data?.current,
21153
+ zones: allZones
21154
+ });
21155
+ if (!over) {
21156
+ dndLog.warn("dragEnd:abort:no-over", { activeId: active.id, reason: "no droppable under pointer at drop time \u2192 item snaps back" });
21157
+ return;
21158
+ }
21133
21159
  const sourceZone = findZoneByItem(active.id);
21134
21160
  const overData = over.data?.current;
21135
21161
  const targetGroup = overData?.dndGroup;
21136
- if (!sourceZone || !targetGroup) return;
21162
+ dndLog.debug("dragEnd:resolved", { sourceGroup: sourceZone?.group, targetGroup, overDataKeys: overData ? Object.keys(overData) : null });
21163
+ if (!sourceZone) {
21164
+ dndLog.warn("dragEnd:abort:no-source-zone", { activeId: active.id });
21165
+ return;
21166
+ }
21167
+ if (!targetGroup) {
21168
+ dndLog.warn("dragEnd:abort:no-target-group", { overId: over.id, overData });
21169
+ return;
21170
+ }
21137
21171
  const targetZone = findZoneByGroup(targetGroup);
21138
- if (!targetZone) return;
21172
+ if (!targetZone) {
21173
+ dndLog.warn("dragEnd:abort:target-zone-not-registered", { targetGroup });
21174
+ return;
21175
+ }
21139
21176
  if (sourceZone.group !== targetZone.group) {
21140
21177
  if (targetZone.dropEvent) {
21141
21178
  const newIndex2 = targetZone.itemIds.indexOf(over.id);
21179
+ dndLog.info("dragEnd:cross-container:emit", {
21180
+ event: targetZone.dropEvent,
21181
+ id: String(active.id),
21182
+ sourceGroup: sourceZone.group,
21183
+ targetGroup: targetZone.group,
21184
+ newIndex: newIndex2 === -1 ? targetZone.itemIds.length : newIndex2
21185
+ });
21142
21186
  eventBus.emit(targetZone.dropEvent, {
21143
21187
  id: String(active.id),
21144
21188
  sourceGroup: sourceZone.group,
21145
21189
  targetGroup: targetZone.group,
21146
21190
  newIndex: newIndex2 === -1 ? targetZone.itemIds.length : newIndex2
21147
21191
  });
21192
+ } else {
21193
+ dndLog.warn("dragEnd:cross-container:no-dropEvent-on-target", { targetGroup: targetZone.group });
21148
21194
  }
21149
21195
  return;
21150
21196
  }
@@ -21156,11 +21202,19 @@ function useDataDnd(args) {
21156
21202
  setLocalOrder(reordered);
21157
21203
  }
21158
21204
  if (sourceZone.reorderEvent) {
21205
+ dndLog.info("dragEnd:reorder:emit", {
21206
+ event: sourceZone.reorderEvent,
21207
+ id: String(active.id),
21208
+ oldIndex,
21209
+ newIndex
21210
+ });
21159
21211
  eventBus.emit(sourceZone.reorderEvent, {
21160
21212
  id: String(active.id),
21161
21213
  oldIndex,
21162
21214
  newIndex
21163
21215
  });
21216
+ } else {
21217
+ dndLog.debug("dragEnd:reorder:no-reorderEvent", { sourceGroup: sourceZone.group });
21164
21218
  }
21165
21219
  },
21166
21220
  [orderedItems, ownGroup, findZoneByItem, findZoneByGroup, eventBus]
@@ -21201,15 +21255,20 @@ function useDataDnd(args) {
21201
21255
  [sortableData, enabled]
21202
21256
  );
21203
21257
  const DropZoneShell = ({ children }) => {
21258
+ const droppableId = `dnd-zone-${zoneId}`;
21204
21259
  const { setNodeRef, isOver } = useDroppable({
21205
- id: `dnd-zone-${zoneId}`,
21260
+ id: droppableId,
21206
21261
  data: sortableData
21207
21262
  });
21263
+ React80__default.useEffect(() => {
21264
+ dndLog.debug("dropzone:isOver:change", { droppableId, group: ownGroup, isOver });
21265
+ }, [droppableId, isOver]);
21208
21266
  return /* @__PURE__ */ jsx(
21209
21267
  Box,
21210
21268
  {
21211
21269
  ref: setNodeRef,
21212
21270
  "data-dnd-zone": ownGroup,
21271
+ "data-dnd-is-over": isOver ? "true" : "false",
21213
21272
  className: isOver ? "ring-2 ring-primary ring-offset-2 rounded-lg transition-all min-h-[3rem]" : "min-h-[3rem] rounded-lg transition-all",
21214
21273
  children
21215
21274
  }
@@ -21219,21 +21278,65 @@ function useDataDnd(args) {
21219
21278
  () => ({ registerZone, unregisterZone }),
21220
21279
  [registerZone, unregisterZone]
21221
21280
  );
21281
+ const handleDragStart = React80__default.useCallback((event) => {
21282
+ const sourceZone = findZoneByItem(event.active.id);
21283
+ dndLog.info("dragStart", {
21284
+ activeId: event.active.id,
21285
+ activeData: event.active.data?.current,
21286
+ sourceGroup: sourceZone?.group,
21287
+ zoneCount: zonesRef.current.size
21288
+ });
21289
+ }, [findZoneByItem]);
21290
+ const handleDragOver = React80__default.useCallback((event) => {
21291
+ dndLog.debug("dragOver", {
21292
+ activeId: event.active.id,
21293
+ overId: event.over?.id,
21294
+ overData: event.over?.data?.current
21295
+ });
21296
+ }, []);
21297
+ const handleDragCancel = React80__default.useCallback((event) => {
21298
+ dndLog.warn("dragCancel", {
21299
+ activeId: event.active.id,
21300
+ reason: "dnd-kit cancelled the drag (escape key, pointer interrupted, or external)"
21301
+ });
21302
+ }, []);
21222
21303
  const wrapContainer = React80__default.useCallback(
21223
21304
  (children) => {
21224
21305
  if (!enabled) return children;
21225
21306
  const strategy = layout === "grid" ? rectSortingStrategy : verticalListSortingStrategy;
21226
21307
  if (!isZone) {
21227
21308
  if (!isRoot) return children;
21228
- return /* @__PURE__ */ jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection, onDragEnd: handleDragEnd, children }) });
21309
+ return /* @__PURE__ */ jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx(
21310
+ DndContext,
21311
+ {
21312
+ sensors,
21313
+ collisionDetection,
21314
+ onDragStart: handleDragStart,
21315
+ onDragOver: handleDragOver,
21316
+ onDragEnd: handleDragEnd,
21317
+ onDragCancel: handleDragCancel,
21318
+ children
21319
+ }
21320
+ ) });
21229
21321
  }
21230
21322
  const inner = /* @__PURE__ */ jsx(DropZoneShell, { children: /* @__PURE__ */ jsx(SortableContext, { items: itemIds, strategy, children }) });
21231
21323
  if (isRoot) {
21232
- return /* @__PURE__ */ jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx(DndContext, { sensors, collisionDetection, onDragEnd: handleDragEnd, children: inner }) });
21324
+ return /* @__PURE__ */ jsx(RootCtx.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx(
21325
+ DndContext,
21326
+ {
21327
+ sensors,
21328
+ collisionDetection,
21329
+ onDragStart: handleDragStart,
21330
+ onDragOver: handleDragOver,
21331
+ onDragEnd: handleDragEnd,
21332
+ onDragCancel: handleDragCancel,
21333
+ children: inner
21334
+ }
21335
+ ) });
21233
21336
  }
21234
21337
  return inner;
21235
21338
  },
21236
- [enabled, isZone, layout, sensors, collisionDetection, handleDragEnd, itemIds, isRoot, rootContextValue]
21339
+ [enabled, isZone, layout, sensors, collisionDetection, handleDragStart, handleDragOver, handleDragEnd, handleDragCancel, itemIds, isRoot, rootContextValue]
21237
21340
  );
21238
21341
  return {
21239
21342
  enabled,
@@ -21243,12 +21346,13 @@ function useDataDnd(args) {
21243
21346
  orderedItems
21244
21347
  };
21245
21348
  }
21246
- var RootCtx;
21349
+ var dndLog, RootCtx;
21247
21350
  var init_useDataDnd = __esm({
21248
21351
  "components/molecules/useDataDnd.tsx"() {
21249
21352
  "use client";
21250
21353
  init_useEventBus();
21251
21354
  init_Box();
21355
+ dndLog = createLogger("almadar:ui:dnd");
21252
21356
  RootCtx = React80__default.createContext(null);
21253
21357
  }
21254
21358
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "4.50.5",
3
+ "version": "4.50.6",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [