@r2digisolutions/components 0.14.20 → 0.14.21

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.
@@ -4,6 +4,7 @@
4
4
  name: string;
5
5
  role?: string;
6
6
  avatarUrl?: string;
7
+ assignees?: { id: string; name: string; avatarUrl?: string | null }[];
7
8
  children?: OrgNode[];
8
9
  }
9
10
 
@@ -17,6 +18,8 @@
17
18
 
18
19
  let selected = $state<string | null>(null);
19
20
 
21
+ const CARD_W = 176;
22
+
20
23
  function initials(name: string) {
21
24
  return name
22
25
  .split(/\s+/)
@@ -24,13 +27,22 @@
24
27
  .map((p) => p[0]?.toUpperCase() ?? '')
25
28
  .join('');
26
29
  }
30
+
31
+ function primaryAvatar(node: OrgNode) {
32
+ return node.avatarUrl ?? node.assignees?.[0]?.avatarUrl ?? null;
33
+ }
34
+
35
+ function primaryLabel(node: OrgNode) {
36
+ if (node.assignees?.length === 1) return node.assignees[0].name;
37
+ return null;
38
+ }
27
39
  </script>
28
40
 
29
41
  {#snippet nodeCard(node: OrgNode)}
30
42
  <button
31
43
  type="button"
32
44
  class={[
33
- 'flex min-w-[140px] max-w-[180px] flex-col items-center gap-1.5 rounded-xl border bg-surface-elevated px-3 py-2.5 text-center shadow-sm transition-all',
45
+ 'flex w-full flex-col items-center gap-1.5 rounded-xl border bg-surface-elevated px-3 py-2.5 text-center shadow-sm transition-all',
34
46
  selected === node.id
35
47
  ? 'border-brand-500 ring-2 ring-brand-500/30'
36
48
  : 'border-border hover:border-brand-400'
@@ -40,8 +52,8 @@
40
52
  onselect?.(node);
41
53
  }}
42
54
  >
43
- {#if node.avatarUrl}
44
- <img src={node.avatarUrl} alt="" class="h-9 w-9 rounded-full object-cover" />
55
+ {#if primaryAvatar(node)}
56
+ <img src={primaryAvatar(node)!} alt="" class="h-9 w-9 rounded-full object-cover" />
45
57
  {:else}
46
58
  <span
47
59
  class="flex h-9 w-9 items-center justify-center rounded-full bg-brand-500/15 text-xs font-semibold text-brand-600 dark:text-brand-300"
@@ -49,43 +61,78 @@
49
61
  {initials(node.name)}
50
62
  </span>
51
63
  {/if}
52
- <span class="truncate text-sm font-medium text-primary">{node.name}</span>
64
+ <span class="line-clamp-2 text-sm leading-snug font-semibold text-primary">{node.name}</span>
65
+ {#if primaryLabel(node)}
66
+ <span class="truncate text-xs text-secondary">{primaryLabel(node)}</span>
67
+ {/if}
53
68
  {#if node.role}
54
69
  <span class="truncate text-[11px] text-muted">{node.role}</span>
55
70
  {/if}
71
+ {#if node.assignees && node.assignees.length > 1}
72
+ <span class="text-[10px] text-muted">+{node.assignees.length - 1} más</span>
73
+ {/if}
56
74
  </button>
57
75
  {/snippet}
58
76
 
59
- {#snippet tree(node: OrgNode)}
60
- <div class="relative flex flex-col items-center">
61
- {@render nodeCard(node)}
62
-
63
- {#if node.children && node.children.length > 0}
64
- <div class="h-5 w-px bg-border" aria-hidden="true"></div>
65
- <div class="relative flex flex-wrap justify-center gap-x-8 gap-y-4">
66
- {#if node.children.length > 1}
77
+ {#snippet childForest(node: OrgNode)}
78
+ {#if node.children?.length}
79
+ {#if node.children.length === 1}
80
+ <div class="flex flex-col items-center">
81
+ <div class="h-6 w-px shrink-0 bg-border" aria-hidden="true"></div>
82
+ {@render branch(node.children[0])}
83
+ </div>
84
+ {:else}
85
+ <div class="flex flex-col items-center">
86
+ <div class="h-6 w-px shrink-0 bg-border" aria-hidden="true"></div>
87
+ <div
88
+ class="relative inline-flex items-start justify-center gap-4 pt-4"
89
+ style:--siblings={node.children.length}
90
+ >
67
91
  <div
68
- class="pointer-events-none absolute left-[12%] right-[12%] top-0 h-px bg-border"
92
+ class="pointer-events-none absolute top-0 h-px bg-border"
93
+ style:left="calc(50% / var(--siblings))"
94
+ style:right="calc(50% / var(--siblings))"
69
95
  aria-hidden="true"
70
96
  ></div>
71
- {/if}
72
- {#each node.children as child (child.id)}
73
- <div class="relative flex flex-col items-center pt-0">
74
- <div class="absolute left-1/2 top-0 h-3 w-px -translate-x-1/2 bg-border" aria-hidden="true"></div>
75
- <div class="pt-3">
76
- {@render tree(child)}
97
+ {#each node.children as child (child.id)}
98
+ <div class="flex shrink-0 flex-col items-center" style:width="{CARD_W}px">
99
+ <div class="h-4 w-px shrink-0 bg-border" aria-hidden="true"></div>
100
+ <div class="w-full">
101
+ {@render nodeCard(child)}
102
+ </div>
77
103
  </div>
78
- </div>
79
- {/each}
104
+ {/each}
105
+ </div>
106
+ <div class="inline-flex items-start justify-center gap-4">
107
+ {#each node.children as child (child.id)}
108
+ <div
109
+ class="flex flex-col items-center pt-2"
110
+ style:min-width="{CARD_W}px"
111
+ >
112
+ {#if child.children?.length}
113
+ {@render childForest(child)}
114
+ {/if}
115
+ </div>
116
+ {/each}
117
+ </div>
80
118
  </div>
81
119
  {/if}
120
+ {/if}
121
+ {/snippet}
122
+
123
+ {#snippet branch(node: OrgNode)}
124
+ <div class="flex flex-col items-center">
125
+ <div class="w-full" style:width="{CARD_W}px">
126
+ {@render nodeCard(node)}
127
+ </div>
128
+ {@render childForest(node)}
82
129
  </div>
83
130
  {/snippet}
84
131
 
85
- <div class={['overflow-x-auto py-2', className]} role="tree" aria-label="Organization chart">
132
+ <div class={['overflow-x-auto py-4', className]} role="tree" aria-label="Organization chart">
86
133
  {#if root}
87
- <div class="inline-flex min-w-full justify-center px-4">
88
- {@render tree(root)}
134
+ <div class="flex justify-center px-4 pb-2">
135
+ {@render branch(root)}
89
136
  </div>
90
137
  {:else}
91
138
  <p class="py-8 text-center text-sm text-muted">No organization data</p>
@@ -3,6 +3,11 @@ export interface OrgNode {
3
3
  name: string;
4
4
  role?: string;
5
5
  avatarUrl?: string;
6
+ assignees?: {
7
+ id: string;
8
+ name: string;
9
+ avatarUrl?: string | null;
10
+ }[];
6
11
  children?: OrgNode[];
7
12
  }
8
13
  interface OrgChartProps {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/components",
3
- "version": "0.14.20",
3
+ "version": "0.14.21",
4
4
  "private": false,
5
5
  "description": "R2DigiSolutions Svelte 5 component library — Atomic Design, Tailwind 4, Light/Dark mode",
6
6
  "license": "MIT",