@asteby/metacore-runtime-react 23.5.0 → 23.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 23.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 36e7cb8: DynamicKanban: las lanes ahora aprovechan el ancho del viewport. Crecen (flex-1) para llenar el contenedor cuando todas caben, con un ancho mínimo legible (280px) y un máximo razonable (420px); el scroll horizontal solo aparece cuando ya no caben. Elimina el espacio muerto a la derecha y las columnas angostas al reducir la ventana.
8
+
3
9
  ## 23.5.0
4
10
 
5
11
  ### Minor Changes
@@ -588,7 +588,7 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, on
588
588
  }
589
589
  }, [api, endpoint, groupByKey, lanePagination, model, records, stageOfCard, t, transitions]);
590
590
  if (loading) {
591
- return (_jsx("div", { className: "flex gap-4 overflow-x-auto p-1", children: [0, 1, 2, 3].map((i) => (_jsxs("div", { className: "w-[300px] shrink-0 space-y-3", children: [_jsx(Skeleton, { className: "h-8 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" })] }, i))) }));
591
+ return (_jsx("div", { className: "flex w-full gap-4 overflow-x-auto p-1", children: [0, 1, 2, 3].map((i) => (_jsxs("div", { className: "min-w-[280px] max-w-[420px] flex-1 shrink-0 space-y-3", children: [_jsx(Skeleton, { className: "h-8 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" })] }, i))) }));
592
592
  }
593
593
  if (!metadata || !groupByKey || stages.length === 0) {
594
594
  return (_jsx("div", { className: "rounded-md border border-dashed p-8 text-center text-sm text-muted-foreground", children: t('kanban.noStages', {
@@ -615,7 +615,7 @@ export function DynamicKanban({ model, endpoint, refreshTrigger, onCardClick, on
615
615
  })
616
616
  : t('kanban.noActiveFilters', {
617
617
  defaultValue: 'Sin filtros',
618
- }) }), _jsxs(Button, { variant: "ghost", size: "sm", className: "h-7 gap-1 text-xs", onClick: clearAll, disabled: activeFilterCount === 0, children: [_jsx(X, { className: "h-3.5 w-3.5" }), t('kanban.clearAll', { defaultValue: 'Limpiar todo' }), activeFilterCount > 0 ? ` (${activeFilterCount})` : ''] })] })] })] }))] }), _jsx(FilterChipsRow, { fields: activeFields, onClearAll: clearAll, "data-testid": "kanban-filter-chips" }), _jsxs(DndContext, { sensors: sensors, onDragStart: onDragStart, onDragEnd: onDragEnd, children: [_jsx("div", { className: "flex min-w-0 gap-4 overflow-x-auto p-1", "data-testid": "kanban-board", children: lanes.map((stage) => {
618
+ }) }), _jsxs(Button, { variant: "ghost", size: "sm", className: "h-7 gap-1 text-xs", onClick: clearAll, disabled: activeFilterCount === 0, children: [_jsx(X, { className: "h-3.5 w-3.5" }), t('kanban.clearAll', { defaultValue: 'Limpiar todo' }), activeFilterCount > 0 ? ` (${activeFilterCount})` : ''] })] })] })] }))] }), _jsx(FilterChipsRow, { fields: activeFields, onClearAll: clearAll, "data-testid": "kanban-filter-chips" }), _jsxs(DndContext, { sensors: sensors, onDragStart: onDragStart, onDragEnd: onDragEnd, children: [_jsx("div", { className: "flex w-full min-w-0 gap-4 overflow-x-auto p-1", "data-testid": "kanban-board", children: lanes.map((stage) => {
619
619
  const allCards = grouped.get(stage.key) ?? [];
620
620
  // Per-lane client-side narrowing (instant, scoped to this
621
621
  // stage). The funnel (field/value) and the lane search
@@ -710,7 +710,12 @@ function KanbanLane({ stage, count, totalCount, serverTotal, hasMore, loadingMor
710
710
  text: laneFilter.text,
711
711
  }
712
712
  : undefined;
713
- return (_jsxs("div", { ref: setNodeRef, className: "group/lane flex w-[300px] shrink-0 flex-col rounded-xl border bg-muted/30 transition-opacity", style: {
713
+ return (_jsxs("div", { ref: setNodeRef,
714
+ // Fluid width: lanes grow (flex-1) to fill the board when they all
715
+ // fit, capped at max-w so a couple of lanes don't stretch absurdly
716
+ // wide. Below min-w the board's overflow-x-auto takes over and the
717
+ // lanes scroll horizontally at their minimum width.
718
+ className: "group/lane flex min-w-[280px] max-w-[420px] flex-1 shrink-0 flex-col rounded-xl border bg-muted/30 transition-opacity", style: {
714
719
  opacity: dimmed ? 0.45 : 1,
715
720
  outline: isOver && !disabled ? '2px solid var(--ring, #3b82f6)' : 'none',
716
721
  outlineOffset: 2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "23.5.0",
3
+ "version": "23.5.1",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -383,6 +383,29 @@ describe('DynamicKanban render', () => {
383
383
  // a secondary field label is present
384
384
  expect(screen.getAllByText('Assignee:').length).toBeGreaterThan(0)
385
385
  })
386
+
387
+ it('lays out fluid lanes: the board fills the width and lanes grow (flex-1) with a min/max width', async () => {
388
+ useMetadataCache.getState().setMetadata('issue', meta())
389
+ const { container } = render(
390
+ <ApiProvider client={fakeApi()}>
391
+ <DynamicKanban model="issue" />
392
+ </ApiProvider>,
393
+ )
394
+ await screen.findByText('Backlog')
395
+ // The board fills the container and scrolls horizontally only on overflow.
396
+ const board = container.querySelector('[data-testid="kanban-board"]')!
397
+ expect(board.className).toContain('w-full')
398
+ expect(board.className).toContain('overflow-x-auto')
399
+ // Each lane grows to fill the available width but never shrinks past a
400
+ // readable min-width nor stretches beyond a sane max-width.
401
+ const lanes = container.querySelectorAll('[data-stage]')
402
+ expect(lanes.length).toBe(4)
403
+ lanes.forEach((lane) => {
404
+ expect(lane.className).toContain('flex-1')
405
+ expect(lane.className).toContain('min-w-[280px]')
406
+ expect(lane.className).toContain('max-w-[420px]')
407
+ })
408
+ })
386
409
  })
387
410
 
388
411
  // The drag itself is wired by dnd-kit (pointer + layout), which happy-dom can't
@@ -877,9 +877,9 @@ export function DynamicKanban({
877
877
 
878
878
  if (loading) {
879
879
  return (
880
- <div className="flex gap-4 overflow-x-auto p-1">
880
+ <div className="flex w-full gap-4 overflow-x-auto p-1">
881
881
  {[0, 1, 2, 3].map((i) => (
882
- <div key={i} className="w-[300px] shrink-0 space-y-3">
882
+ <div key={i} className="min-w-[280px] max-w-[420px] flex-1 shrink-0 space-y-3">
883
883
  <Skeleton className="h-8 w-full" />
884
884
  <Skeleton className="h-24 w-full" />
885
885
  <Skeleton className="h-24 w-full" />
@@ -1023,7 +1023,7 @@ export function DynamicKanban({
1023
1023
  />
1024
1024
 
1025
1025
  <DndContext sensors={sensors} onDragStart={onDragStart} onDragEnd={onDragEnd}>
1026
- <div className="flex min-w-0 gap-4 overflow-x-auto p-1" data-testid="kanban-board">
1026
+ <div className="flex w-full min-w-0 gap-4 overflow-x-auto p-1" data-testid="kanban-board">
1027
1027
  {lanes.map((stage) => {
1028
1028
  const allCards = grouped.get(stage.key) ?? []
1029
1029
  // Per-lane client-side narrowing (instant, scoped to this
@@ -1309,7 +1309,11 @@ function KanbanLane({
1309
1309
  return (
1310
1310
  <div
1311
1311
  ref={setNodeRef}
1312
- className="group/lane flex w-[300px] shrink-0 flex-col rounded-xl border bg-muted/30 transition-opacity"
1312
+ // Fluid width: lanes grow (flex-1) to fill the board when they all
1313
+ // fit, capped at max-w so a couple of lanes don't stretch absurdly
1314
+ // wide. Below min-w the board's overflow-x-auto takes over and the
1315
+ // lanes scroll horizontally at their minimum width.
1316
+ className="group/lane flex min-w-[280px] max-w-[420px] flex-1 shrink-0 flex-col rounded-xl border bg-muted/30 transition-opacity"
1313
1317
  style={{
1314
1318
  opacity: dimmed ? 0.45 : 1,
1315
1319
  outline: isOver && !disabled ? '2px solid var(--ring, #3b82f6)' : 'none',