@stubber/ui 1.4.1 → 1.6.0

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.
@@ -0,0 +1,213 @@
1
+ <script>
2
+ import { createEventDispatcher, tick } from "svelte";
3
+ import * as Popover from "@stubber/ui/popover";
4
+ import * as Command from "@stubber/ui/command";
5
+ import * as Tooltip from "@stubber/ui/tooltip";
6
+ import { Button } from "@stubber/ui/button";
7
+ import { toast } from "svelte-sonner";
8
+
9
+ export let orgs = [];
10
+ export let selectedorguuid = undefined;
11
+ export let createOrgLink = "";
12
+ export let loading = false;
13
+
14
+ $: selectedOrg = orgs.find((org) => org.orguuid === selectedorguuid);
15
+
16
+ const dispatch = createEventDispatcher();
17
+ const alertColorMap = {
18
+ error: "danger-500",
19
+ warning: "warning-500",
20
+ success: "success-500",
21
+ };
22
+
23
+ // Combobox state
24
+ let open = false;
25
+ let searchValue = "";
26
+
27
+ // Filter orgs based on search
28
+ $: filteredOrgs = orgs.filter((org) =>
29
+ org.label.toLowerCase().includes(searchValue.toLowerCase())
30
+ );
31
+
32
+ function selectOrg(orguuid) {
33
+ dispatch("selectOrg", orguuid);
34
+ }
35
+
36
+ function closeAndFocusTrigger(triggerId) {
37
+ open = false;
38
+ searchValue = "";
39
+ tick().then(() => {
40
+ document.getElementById(triggerId)?.focus();
41
+ });
42
+ }
43
+
44
+ function copyToClipboard(uuid, event) {
45
+ if (event) {
46
+ event.stopPropagation();
47
+ event.preventDefault();
48
+ }
49
+ navigator.clipboard.writeText(uuid);
50
+ toast.success("UUID copied to clipboard!");
51
+ }
52
+ </script>
53
+
54
+ <Popover.Root bind:open let:ids>
55
+ <Popover.Trigger asChild let:builder>
56
+ <Button
57
+ builders={[builder]}
58
+ id={ids.trigger}
59
+ variant="outline"
60
+ role="combobox"
61
+ aria-expanded={open}
62
+ class="w-full sm:w-[280px] pl-3 pr-3 py-2 h-auto border-surface-100 transition-colors group justify-start"
63
+ >
64
+ <div class="flex items-center w-full">
65
+ <div class="flex items-center justify-center mr-3">
66
+ {#if selectedOrg?.filesrc && !loading}
67
+ <img
68
+ class="h-[25px] w-[25px] object-cover rounded-full"
69
+ src={selectedOrg.filesrc}
70
+ alt={selectedOrg.label}
71
+ />
72
+ {:else if selectedOrg?.placeholderColor}
73
+ <div
74
+ class="h-[25px] w-[25px] rounded-full"
75
+ style="background-color: {selectedOrg.placeholderColor}"
76
+ />
77
+ {:else}
78
+ <div class="h-[25px] w-[25px] rounded-full bg-surface-100" />
79
+ {/if}
80
+ </div>
81
+
82
+ {#if loading}
83
+ <span class="h-[25px] w-40 bg-surface-100 rounded-md" />
84
+ {:else}
85
+ <div class="w-full text-left truncate">
86
+ <p class="text-label text-surface-900 truncate">
87
+ {selectedOrg?.label ?? "No Org"}
88
+ </p>
89
+ {#if selectedOrg?.alert}
90
+ <div class="flex items-center space-x-1">
91
+ <span
92
+ class="h-[6px] w-[6px] bg-{alertColorMap[selectedOrg.alert?.type]} rounded-full"
93
+ />
94
+ <p class="text-small italic text-{alertColorMap[selectedOrg.alert?.type]}">
95
+ {selectedOrg.alert?.message}
96
+ </p>
97
+ </div>
98
+ {/if}
99
+ </div>
100
+ {/if}
101
+
102
+ {#if selectedOrg}
103
+ <Tooltip.Root openDelay={0} disableHoverableContent={true}>
104
+ <Tooltip.Trigger>
105
+ <div
106
+ class="opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity ml-2 mr-2"
107
+ >
108
+ <i
109
+ role="button"
110
+ tabindex="0"
111
+ on:click={(e) => {
112
+ e.stopPropagation();
113
+ copyToClipboard(selectedOrg.orguuid, e);
114
+ }}
115
+ on:keydown={(e) => {
116
+ if (e.key === "Enter" || e.key === " ") {
117
+ e.stopPropagation();
118
+ copyToClipboard(selectedOrg.orguuid, e);
119
+ }
120
+ }}
121
+ class="far fa-copy text-surface-400 cursor-pointer"
122
+ />
123
+ </div>
124
+ </Tooltip.Trigger>
125
+ <Tooltip.Content>Copy UUID</Tooltip.Content>
126
+ </Tooltip.Root>
127
+ {/if}
128
+ </div>
129
+ </Button>
130
+ </Popover.Trigger>
131
+
132
+ <Popover.Content class="w-full sm:w-[280px] p-0">
133
+ <Command.Root shouldFilter={false}>
134
+ <Command.Input placeholder="Search organizations..." bind:value={searchValue} />
135
+ <Command.Empty>No organizations found.</Command.Empty>
136
+ <Command.Group>
137
+ {#each filteredOrgs as org}
138
+ <div class="relative group">
139
+ <Command.Item
140
+ value={org.orguuid}
141
+ onSelect={() => {
142
+ selectOrg(org.orguuid);
143
+ closeAndFocusTrigger(ids.trigger);
144
+ }}
145
+ class="pr-12"
146
+ >
147
+ <div class="flex items-center w-full">
148
+ <div class="flex items-center justify-center mr-3">
149
+ {#if org.filesrc}
150
+ <img
151
+ class="h-[25px] w-[25px] object-cover rounded-full"
152
+ src={org.filesrc}
153
+ alt={org.label}
154
+ />
155
+ {:else if org.placeholderColor}
156
+ <div
157
+ class="h-[25px] w-[25px] rounded-full"
158
+ style="background-color: {org.placeholderColor}"
159
+ />
160
+ {:else}
161
+ <div class="h-[25px] w-[25px] rounded-full bg-surface-100" />
162
+ {/if}
163
+ </div>
164
+
165
+ <div class="flex-1 text-left">
166
+ <p class="text-label text-surface-900">
167
+ {org.label}
168
+ </p>
169
+ {#if org.alert}
170
+ <div class="flex items-center space-x-1">
171
+ <span
172
+ class="h-[6px] w-[6px] bg-{alertColorMap[org.alert.type]} rounded-full"
173
+ />
174
+ <p class="text-small italic text-{alertColorMap[org.alert.type]}">
175
+ {org.alert?.message}
176
+ </p>
177
+ </div>
178
+ {/if}
179
+ </div>
180
+ </div>
181
+ </Command.Item>
182
+
183
+ <!-- Copy button positioned absolutely -->
184
+ <div class="absolute right-2 top-1/2 -translate-y-1/2">
185
+ <Button
186
+ variant="ghost"
187
+ size="icon"
188
+ class="h-8 w-8 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 transition-opacity"
189
+ on:click={(e) => {
190
+ e.stopPropagation();
191
+ copyToClipboard(org.orguuid, e);
192
+ }}
193
+ >
194
+ <i class="far fa-copy text-surface-400" />
195
+ </Button>
196
+ </div>
197
+ </div>
198
+ {/each}
199
+ </Command.Group>
200
+
201
+ {#if createOrgLink}
202
+ <Command.Separator />
203
+ <a
204
+ href={createOrgLink}
205
+ class="flex items-center px-8 py-2 text-sm text-primary-500 hover:bg-accent rounded-sm"
206
+ >
207
+ <i class="far fa-plus mr-2" />
208
+ <span>Create org</span>
209
+ </a>
210
+ {/if}
211
+ </Command.Root>
212
+ </Popover.Content>
213
+ </Popover.Root>
@@ -0,0 +1,35 @@
1
+ /** @typedef {typeof __propDef.props} OrgSwitcherNewProps */
2
+ /** @typedef {typeof __propDef.events} OrgSwitcherNewEvents */
3
+ /** @typedef {typeof __propDef.slots} OrgSwitcherNewSlots */
4
+ export default class OrgSwitcherNew extends SvelteComponent<{
5
+ orgs?: any[] | undefined;
6
+ selectedorguuid?: any;
7
+ createOrgLink?: string | undefined;
8
+ loading?: boolean | undefined;
9
+ }, {
10
+ selectOrg: CustomEvent<any>;
11
+ } & {
12
+ [evt: string]: CustomEvent<any>;
13
+ }, {}> {
14
+ }
15
+ export type OrgSwitcherNewProps = typeof __propDef.props;
16
+ export type OrgSwitcherNewEvents = typeof __propDef.events;
17
+ export type OrgSwitcherNewSlots = typeof __propDef.slots;
18
+ import { SvelteComponent } from "svelte";
19
+ declare const __propDef: {
20
+ props: {
21
+ orgs?: any[] | undefined;
22
+ selectedorguuid?: any;
23
+ createOrgLink?: string | undefined;
24
+ loading?: boolean | undefined;
25
+ };
26
+ events: {
27
+ selectOrg: CustomEvent<any>;
28
+ } & {
29
+ [evt: string]: CustomEvent<any>;
30
+ };
31
+ slots: {};
32
+ exports?: undefined;
33
+ bindings?: undefined;
34
+ };
35
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stubber/ui",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && pnpm run package && node ./fix_dts_imports.js",