@invopop/popui 0.1.56 → 0.1.58

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.
@@ -1,36 +1,75 @@
1
1
  <script lang="ts">
2
2
  import clsx from 'clsx'
3
3
  import type { DataListItemProps } from './types'
4
+ import BaseButton from './BaseButton.svelte'
5
+ import { Duplicate, ExternalLink } from '@invopop/ui-icons'
4
6
 
5
7
  let {
6
8
  label = '',
7
9
  value = '',
8
10
  monospaced = false,
9
- monospacedNums = false,
10
- fullWidth = false,
11
- children
11
+ children,
12
+ onCopy,
13
+ onLink
12
14
  }: DataListItemProps = $props()
13
15
 
14
16
  let valueStyles = $derived(
15
- clsx('text-foreground font-medium text-base', {
16
- 'font-mono': monospaced,
17
- 'slashed-zero tabular-nums lining-nums': monospacedNums,
18
- 'w-full': fullWidth
17
+ clsx('text-foreground font-medium text-base truncate min-w-0', {
18
+ 'font-mono slashed-zero tabular-nums lining-nums': monospaced
19
19
  })
20
20
  )
21
+
22
+ let clickAction = $derived(onCopy || onLink)
23
+
24
+ const handleAreaClick = (e: MouseEvent) => {
25
+ // Only handle click if not clicking on a button
26
+ if ((e.target as HTMLElement).closest('button')) return
27
+
28
+ if (onCopy) {
29
+ onCopy()
30
+ } else if (onLink) {
31
+ onLink()
32
+ }
33
+ }
21
34
  </script>
22
35
 
23
- <div class="flex gap-6 items-center px-3 py-1 rounded-lg hover:bg-background-default-secondary">
36
+ <div class="flex gap-6 items-center group">
24
37
  <div class="text-foreground-default-secondary text-base min-w-[125px]">
25
38
  {label}
26
39
  </div>
27
- <div class="flex gap-1 items-center">
28
- <div class={valueStyles}>
29
- {#if children}
30
- {@render children()}
31
- {:else}
32
- {value}
33
- {/if}
40
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
41
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
42
+ <div
43
+ class={clsx(
44
+ 'flex flex-1 gap-1 items-center group-hover:bg-background-default-secondary py-1 pl-2 pr-1 rounded-md min-w-0',
45
+ { 'cursor-pointer': clickAction }
46
+ )}
47
+ onclick={clickAction ? handleAreaClick : undefined}
48
+ >
49
+ <div class="flex-1 min-w-0">
50
+ <div class={valueStyles}>
51
+ {#if children}
52
+ {@render children()}
53
+ {:else}
54
+ {value}
55
+ {/if}
56
+ </div>
34
57
  </div>
58
+ {#if onCopy}
59
+ <BaseButton
60
+ variant="outline"
61
+ icon={Duplicate}
62
+ onclick={onCopy}
63
+ class="opacity-0 group-hover:opacity-100 transition-opacity"
64
+ />
65
+ {/if}
66
+ {#if onLink}
67
+ <BaseButton
68
+ variant="outline"
69
+ icon={ExternalLink}
70
+ onclick={onLink}
71
+ class="opacity-0 group-hover:opacity-100 transition-opacity"
72
+ />
73
+ {/if}
35
74
  </div>
36
75
  </div>
@@ -8,6 +8,7 @@
8
8
  import { ChevronRight } from '@steeze-ui/heroicons'
9
9
  import { slide } from 'svelte/transition'
10
10
  import { flip } from 'svelte/animate'
11
+ import clsx from 'clsx'
11
12
  import {
12
13
  draggable as makeDraggable,
13
14
  dropTargetForElements
@@ -53,6 +54,16 @@
53
54
 
54
55
  type DndItem = DrawerOption & { id: string }
55
56
 
57
+ let containerClasses = $derived(
58
+ clsx(
59
+ widthClass,
60
+ 'border border-border rounded-2xl shadow-lg bg-background flex flex-col py-1 max-h-[568px] overflow-y-auto list-none',
61
+ {
62
+ '[scrollbar-width:none] [&::-webkit-scrollbar]:hidden': draggable
63
+ }
64
+ )
65
+ )
66
+
56
67
  let selectedItems = $derived(items.filter((i) => i.selected))
57
68
  let hasGroups = $derived(groups && groups.length > 0)
58
69
  let { groupedItems, ungroupedItems } = $derived.by(() => {
@@ -485,7 +496,7 @@
485
496
 
486
497
  <div
487
498
  bind:this={containerRef}
488
- class="{widthClass} border border-border rounded-2xl shadow-lg bg-background flex flex-col py-1 max-h-[568px] list-none"
499
+ class={containerClasses}
489
500
  >
490
501
  {@render children?.()}
491
502
 
@@ -2,7 +2,7 @@
2
2
  import clsx from 'clsx'
3
3
  import type { FeedItemDetailProps } from './types.ts'
4
4
  import FeedIconStatus from './FeedIconStatus.svelte'
5
- import UuidCopy from './UuidCopy.svelte'
5
+ import ButtonUuidCopy from './ButtonUuidCopy.svelte'
6
6
  import FeedEvents from './FeedEvents.svelte'
7
7
  import { slide } from 'svelte/transition'
8
8
  import SeparatorHorizontal from './SeparatorHorizontal.svelte'
@@ -52,7 +52,7 @@
52
52
  <div class="pl-3 py-1 pr-2.5 flex items-center space-x-0.5">
53
53
  <span class="text-sm text-foreground-default-secondary whitespace-nowrap">{idLabel}</span>
54
54
  {#if uuid}
55
- <UuidCopy {uuid} full small {onCopied} />
55
+ <ButtonUuidCopy {uuid} full oncopied={onCopied} />
56
56
  {/if}
57
57
  </div>
58
58
  {#if events.length}
@@ -4,12 +4,15 @@
4
4
  import type { InputToggleProps } from './types'
5
5
  import { cn } from './utils.js'
6
6
  import { onMount } from 'svelte'
7
+ import { TooltipAutoHide, TooltipContent, TooltipTrigger } from './tooltip'
7
8
  const sw = createSwitch({ label: 'Set Preference' })
8
9
 
9
10
  let {
10
11
  id = Math.random().toString(36).slice(2, 7),
11
12
  label = '',
12
13
  checked = $bindable(false),
14
+ disabled = false,
15
+ hint,
13
16
  onchange,
14
17
  class: className = ''
15
18
  }: InputToggleProps = $props()
@@ -35,7 +38,8 @@
35
38
  {
36
39
  'bg-background-default-tertiary': !$sw.checked,
37
40
  'bg-background-accent': $sw.checked,
38
- 'transition-colors duration-200 ease-in-out': hasInteracted
41
+ 'transition-colors duration-200 ease-in-out': hasInteracted,
42
+ 'opacity-30 cursor-not-allowed': disabled
39
43
  }
40
44
  )
41
45
  )
@@ -51,19 +55,45 @@
51
55
  )
52
56
  )
53
57
 
58
+ let labelStyles = $derived(
59
+ clsx(
60
+ 'inline-flex items-center gap-2',
61
+ {
62
+ 'cursor-not-allowed': disabled,
63
+ 'cursor-pointer': !disabled
64
+ }
65
+ )
66
+ )
67
+
54
68
  function handleChange() {
69
+ if (disabled) return
55
70
  hasInteracted = true
56
71
  onchange?.($sw.checked)
57
72
  checked = $sw.checked
58
73
  }
59
74
  </script>
60
75
 
61
- <label for={id} class={cn("inline-flex items-center gap-2 cursor-pointer", className)}>
62
- <button {id} class={toggleStyles} use:sw.toggle onclick={handleChange}>
63
- <span class="sr-only">Use setting</span>
64
- <span aria-hidden="true" class={circleStyles}></span>
65
- </button>
66
- {#if label}
67
- <span class="text-base text-foreground">{label}</span>
68
- {/if}
69
- </label>
76
+ {#snippet toggleContent()}
77
+ <label for={id} class={cn(labelStyles, className)}>
78
+ <button {id} class={toggleStyles} use:sw.toggle onclick={handleChange} disabled={disabled}>
79
+ <span class="sr-only">Use setting</span>
80
+ <span aria-hidden="true" class={circleStyles}></span>
81
+ </button>
82
+ {#if label}
83
+ <span class="text-base text-foreground">{label}</span>
84
+ {/if}
85
+ </label>
86
+ {/snippet}
87
+
88
+ {#if disabled && hint}
89
+ <TooltipAutoHide>
90
+ <TooltipTrigger>
91
+ {@render toggleContent()}
92
+ </TooltipTrigger>
93
+ <TooltipContent>
94
+ {hint}
95
+ </TooltipContent>
96
+ </TooltipAutoHide>
97
+ {:else}
98
+ {@render toggleContent()}
99
+ {/if}
@@ -126,17 +126,17 @@
126
126
  {
127
127
  size: 'sm',
128
128
  iconOnly: true,
129
- class: 'w-6'
129
+ class: 'w-6 shrink-0'
130
130
  },
131
131
  {
132
132
  size: 'md',
133
133
  iconOnly: true,
134
- class: 'w-7'
134
+ class: 'w-7 shrink-0'
135
135
  },
136
136
  {
137
137
  size: 'lg',
138
138
  iconOnly: true,
139
- class: 'w-8'
139
+ class: 'w-8 shrink-0'
140
140
  },
141
141
  {
142
142
  stackedLeft: true,
@@ -201,15 +201,7 @@
201
201
  let iconOnly = $derived(!children)
202
202
  let hasIcon = $derived(!!icon && !iconOnly)
203
203
 
204
- let iconSize = $derived.by(() => {
205
- if (shortcut) return 'size-3'
206
-
207
- return {
208
- sm: 'size-3',
209
- md: 'size-4',
210
- lg: 'size-4'
211
- }[size]
212
- })
204
+ let iconSize = $derived(shortcut ? 'size-3' : 'size-4')
213
205
 
214
206
  // For icon-right, we need to reverse the padding
215
207
  let paddingClass = $derived(
@@ -240,7 +232,7 @@
240
232
 
241
233
  {#snippet buttonContent()}
242
234
  <div
243
- class={clsx('inline-flex items-center transition-transform group-active:translate-y-px', {
235
+ class={clsx('inline-flex items-center transition-transform group-active/button:translate-y-px', {
244
236
  'gap-1': !iconOnly && !shortcut,
245
237
  'gap-1.5': !iconOnly && shortcut
246
238
  })}
@@ -271,6 +263,7 @@
271
263
  data-slot="button"
272
264
  class={cn(
273
265
  buttonVariants({ variant, size, iconOnly, hasIcon, stackedLeft, stackedRight }),
266
+ 'group/button',
274
267
  iconPosition === 'right' && 'flex-row-reverse',
275
268
  paddingClass,
276
269
  className
@@ -289,7 +282,7 @@
289
282
  data-slot="button"
290
283
  class={cn(
291
284
  buttonVariants({ variant, size, iconOnly, hasIcon, stackedLeft, stackedRight }),
292
- 'group',
285
+ 'group/button',
293
286
  iconPosition === 'right' && 'flex-row-reverse',
294
287
  paddingClass,
295
288
  className
@@ -103,13 +103,18 @@
103
103
 
104
104
  {#snippet toggleAction(item: DrawerOption)}
105
105
  {@const column = table.getColumn(String(item.value))}
106
- {#if column?.getCanHide()}
107
- <InputToggle
108
- class="cursor-default"
109
- checked={column?.getIsVisible() ?? false}
110
- onchange={(v) => column?.toggleVisibility(!!v)}
111
- />
112
- {/if}
106
+ {@const canHide = column?.getCanHide() ?? false}
107
+ <InputToggle
108
+ class="cursor-default"
109
+ checked={column?.getIsVisible() ?? false}
110
+ disabled={!canHide}
111
+ hint={!canHide ? 'This column cannot be hidden' : undefined}
112
+ onchange={(v) => {
113
+ if (canHide) {
114
+ column?.toggleVisibility(!!v)
115
+ }
116
+ }}
117
+ />
113
118
  {/snippet}
114
119
 
115
120
  <BaseDropdown class="ms-auto hidden lg:flex">
package/dist/index.d.ts CHANGED
@@ -75,7 +75,6 @@ import { Tooltip } from './tooltip';
75
75
  import { TooltipContent } from './tooltip';
76
76
  import { TooltipTrigger } from './tooltip';
77
77
  import { TooltipAutoHide } from './tooltip';
78
- import UuidCopy from './UuidCopy.svelte';
79
78
  import { resolveIcon } from './helpers.js';
80
79
  import { getCountryName } from './helpers.js';
81
80
  import { getStatusType } from './helpers.js';
@@ -87,4 +86,4 @@ import { FlexRender } from './data-table';
87
86
  import { createSvelteTable } from './data-table';
88
87
  import { renderComponent } from './data-table';
89
88
  import { renderSnippet } from './data-table';
90
- export { AlertDialog, BaseButton, BaseCard, BaseCounter, BaseDropdown, BaseFlag, BaseTableActions, Breadcrumbs, ButtonFile, ButtonSearch, ButtonUuidCopy, CardCheckbox, CardRelation, CompanySelector, CounterWidget, DataListItem, DatePicker, DrawerContext, DrawerContextItem, DrawerContextSeparator, DropdownSelect, DropdownSelectGroup, EmptyState, FeedEvents, FeedIconEvent, FeedIconStatus, FeedItem, FeedItemDetail, FeedViewer, GlobalSearch, InputCheckbox, InputError, InputLabel, InputRadio, InputSearch, InputSelect, InputText, InputTextarea, InputToggle, MenuItem, MenuItemCollapsible, Notification, ProfileAvatar, ProgressBar, ProgressBarCircle, SeparatorHorizontal, ShortcutWrapper, Skeleton, SkeletonAvatar, SkeletonCard, SkeletonList, StatusLabel, StepIcon, StepIconList, Table, TableBody, TableCaption, TableFooter, TableHeader, TableRow, TableHead, TableCell, Tabs, TabsContent, TabsList, TabsTrigger, TagBeta, TagProgress, TagSearch, TagStatus, TitleMain, TitleSection, Toaster, Tooltip, TooltipContent, TooltipTrigger, TooltipAutoHide, UuidCopy, resolveIcon, getCountryName, getStatusType, buttonVariants, DataTable, DataTableToolbar, DataTableViewOptions, FlexRender, createSvelteTable, renderComponent, renderSnippet };
89
+ export { AlertDialog, BaseButton, BaseCard, BaseCounter, BaseDropdown, BaseFlag, BaseTableActions, Breadcrumbs, ButtonFile, ButtonSearch, ButtonUuidCopy, CardCheckbox, CardRelation, CompanySelector, CounterWidget, DataListItem, DatePicker, DrawerContext, DrawerContextItem, DrawerContextSeparator, DropdownSelect, DropdownSelectGroup, EmptyState, FeedEvents, FeedIconEvent, FeedIconStatus, FeedItem, FeedItemDetail, FeedViewer, GlobalSearch, InputCheckbox, InputError, InputLabel, InputRadio, InputSearch, InputSelect, InputText, InputTextarea, InputToggle, MenuItem, MenuItemCollapsible, Notification, ProfileAvatar, ProgressBar, ProgressBarCircle, SeparatorHorizontal, ShortcutWrapper, Skeleton, SkeletonAvatar, SkeletonCard, SkeletonList, StatusLabel, StepIcon, StepIconList, Table, TableBody, TableCaption, TableFooter, TableHeader, TableRow, TableHead, TableCell, Tabs, TabsContent, TabsList, TabsTrigger, TagBeta, TagProgress, TagSearch, TagStatus, TitleMain, TitleSection, Toaster, Tooltip, TooltipContent, TooltipTrigger, TooltipAutoHide, resolveIcon, getCountryName, getStatusType, buttonVariants, DataTable, DataTableToolbar, DataTableViewOptions, FlexRender, createSvelteTable, renderComponent, renderSnippet };
package/dist/index.js CHANGED
@@ -68,7 +68,6 @@ import TitleMain from './TitleMain.svelte'
68
68
  import TitleSection from './TitleSection.svelte'
69
69
  import { Toaster } from './sonner'
70
70
  import { Tooltip, TooltipContent, TooltipTrigger, TooltipAutoHide } from './tooltip'
71
- import UuidCopy from './UuidCopy.svelte'
72
71
  import { resolveIcon, getCountryName, getStatusType } from './helpers.js'
73
72
  import { buttonVariants } from './button/button.svelte' // Ensure button styles are included
74
73
  import {
@@ -159,7 +158,6 @@ export {
159
158
  TooltipContent,
160
159
  TooltipTrigger,
161
160
  TooltipAutoHide,
162
- UuidCopy,
163
161
  resolveIcon,
164
162
  getCountryName,
165
163
  getStatusType,
@@ -20,7 +20,7 @@
20
20
  {sideOffset}
21
21
  {side}
22
22
  class={cn(
23
- 'bg-background-default-negative border border-border-inverse z-50 rounded-md px-2 py-1 text-sm font-medium text-foreground-inverse leading-5 tracking-tight shadow-md',
23
+ 'bg-background-default-negative border border-border-inverse z-[1002] rounded-md px-2 py-1 text-sm font-medium text-foreground-inverse leading-5 tracking-tight shadow-md',
24
24
  className
25
25
  )}
26
26
  >
@@ -29,7 +29,7 @@
29
29
  {#snippet child({ props })}
30
30
  <div
31
31
  class={cn(
32
- 'bg-background-default-negative z-50 size-2.5 rotate-45 rounded-[2px]',
32
+ 'bg-background-default-negative z-[1002] size-2.5 rotate-45 rounded-[2px]',
33
33
  'data-[side=top]:translate-x-1/2 data-[side=top]:translate-y-[calc(-50%_+_2px)]',
34
34
  'data-[side=bottom]:-translate-x-1/2 data-[side=bottom]:-translate-y-[calc(-50%_+_1px)]',
35
35
  'data-[side=right]:translate-x-[calc(50%_+_2px)] data-[side=right]:translate-y-1/2',
package/dist/types.d.ts CHANGED
@@ -96,7 +96,6 @@ export type TableField = {
96
96
  helperIcons?: (data: TableDataRow) => TableIcon[];
97
97
  monospaced?: boolean;
98
98
  nowrap?: boolean;
99
- monospacedNums?: boolean;
100
99
  rightAlign?: boolean;
101
100
  isCountry?: boolean;
102
101
  copy?: boolean;
@@ -309,9 +308,10 @@ export interface DataListItemProps {
309
308
  label?: string;
310
309
  value?: string;
311
310
  monospaced?: boolean;
312
- monospacedNums?: boolean;
313
311
  fullWidth?: boolean;
314
312
  children?: Snippet;
313
+ onCopy?: () => void;
314
+ onLink?: () => void;
315
315
  }
316
316
  export interface DatePickerProps {
317
317
  label?: string;
@@ -506,6 +506,8 @@ export interface InputToggleProps {
506
506
  id?: string;
507
507
  checked?: boolean;
508
508
  label?: string;
509
+ disabled?: boolean;
510
+ hint?: string;
509
511
  onchange?: (checked: boolean) => void;
510
512
  [key: string]: any;
511
513
  }
@@ -585,17 +587,4 @@ export interface ShortcutWrapperProps {
585
587
  theme?: 'light' | 'navigation';
586
588
  children?: Snippet;
587
589
  }
588
- export interface UuidCopyProps {
589
- uuid?: string;
590
- small?: boolean;
591
- dark?: boolean;
592
- rightAlign?: boolean;
593
- prefixLength?: number;
594
- suffixLength?: number;
595
- full?: boolean;
596
- compact?: boolean;
597
- link?: boolean;
598
- onCopied?: (uuid: string) => void;
599
- onLinkClick?: (uuid: string) => void;
600
- }
601
590
  export type { DataTableColumn, DataTableProps, CellType, TextCellConfig, BooleanCellConfig, TagCellConfig, DateCellConfig, CurrencyCellConfig, CellConfig } from './data-table/data-table-types.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@invopop/popui",
3
3
  "license": "MIT",
4
- "version": "0.1.56",
4
+ "version": "0.1.58",
5
5
  "repository": {
6
6
  "url": "https://github.com/invopop/popui"
7
7
  },
@@ -1,70 +0,0 @@
1
- <script lang="ts">
2
- import { Duplicate, ExternalLink } from '@invopop/ui-icons'
3
- import { Icon } from '@steeze-ui/svelte-icon'
4
- import clsx from 'clsx'
5
- import type { UuidCopyProps } from './types'
6
-
7
- let {
8
- uuid = '',
9
- small = false,
10
- dark = false,
11
- rightAlign = false,
12
- prefixLength = 4,
13
- suffixLength = 4,
14
- full = false,
15
- compact = false,
16
- link = false,
17
- onCopied,
18
- onLinkClick
19
- }: UuidCopyProps = $props()
20
-
21
- function shortenString(inputString: string, prefixLength: number, suffixLength: number) {
22
- if (inputString.length <= prefixLength + suffixLength) {
23
- return inputString // Return the whole string if it's too short
24
- }
25
-
26
- const prefix = inputString.substring(0, prefixLength)
27
- const suffix = inputString.substring(inputString.length - suffixLength)
28
-
29
- return prefix + '...' + suffix
30
- }
31
-
32
- let formattedUuid = $derived(full ? uuid : shortenString(uuid, prefixLength, suffixLength))
33
- let styles = $derived(
34
- clsx({
35
- 'justify-end': rightAlign,
36
- 'text-sm': small,
37
- 'text-base': !small,
38
- 'text-foreground': dark,
39
- 'text-foreground-default-secondary': !dark,
40
- 'justify-between': !compact,
41
- 'w-full': full,
42
- 'border border-border rounded-md pl-2.5 pr-2 py-[5px]': !full
43
- })
44
- )
45
-
46
- async function handleClick(event: MouseEvent) {
47
- event.stopPropagation()
48
- await navigator.clipboard.writeText(uuid)
49
- onCopied?.(uuid)
50
- }
51
-
52
- async function handleIconClick(event: MouseEvent) {
53
- event.stopPropagation()
54
- await navigator.clipboard.writeText(uuid)
55
- if (link) {
56
- onLinkClick?.(uuid)
57
- } else {
58
- onCopied?.(uuid)
59
- }
60
- }
61
- </script>
62
-
63
- <div class="{styles} relative inline-flex items-center space-x-1 text-left whitespace-nowrap">
64
- <button class="tracking-wide font-mono text-base cursor-pointer" onclick={handleClick}>
65
- {formattedUuid}
66
- </button>
67
- <button class="p-1 cursor-pointer" onclick={handleIconClick}>
68
- <Icon src={link ? ExternalLink : Duplicate} class="w-4 h-4 text-foreground-default-secondary" />
69
- </button>
70
- </div>
@@ -1,4 +0,0 @@
1
- import type { UuidCopyProps } from './types';
2
- declare const UuidCopy: import("svelte").Component<UuidCopyProps, {}, "">;
3
- type UuidCopy = ReturnType<typeof UuidCopy>;
4
- export default UuidCopy;