@insymetri/styleguide 0.1.73 → 0.1.74

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.
@@ -12,6 +12,8 @@
12
12
  iconName?: IconName
13
13
  loading?: boolean
14
14
  disabled?: boolean
15
+ /** Stretch to fill the available width. */
16
+ fullWidth?: boolean
15
17
  children?: Snippet
16
18
  class?: string
17
19
  ref?: HTMLButtonElement | HTMLAnchorElement
@@ -28,6 +30,7 @@
28
30
  iconName,
29
31
  loading = false,
30
32
  disabled = false,
33
+ fullWidth = false,
31
34
  children,
32
35
  class: className,
33
36
  href,
@@ -125,7 +128,7 @@
125
128
  <a
126
129
  bind:this={ref}
127
130
  {href}
128
- class={cn(baseClasses, variantClasses[variant], resolvedSizeClasses, className)}
131
+ class={cn(baseClasses, variantClasses[variant], resolvedSizeClasses, fullWidth && 'w-full', className)}
129
132
  {onclick}
130
133
  {...restProps as HTMLAnchorAttributes}
131
134
  >
@@ -135,7 +138,7 @@
135
138
  <button
136
139
  bind:this={ref}
137
140
  disabled={isDisabled}
138
- class={cn(baseClasses, variantClasses[variant], resolvedSizeClasses, className)}
141
+ class={cn(baseClasses, variantClasses[variant], resolvedSizeClasses, fullWidth && 'w-full', className)}
139
142
  onclick={handleClick}
140
143
  {...restProps as HTMLButtonAttributes}
141
144
  >
@@ -7,6 +7,8 @@ type BaseProps = {
7
7
  iconName?: IconName;
8
8
  loading?: boolean;
9
9
  disabled?: boolean;
10
+ /** Stretch to fill the available width. */
11
+ fullWidth?: boolean;
10
12
  children?: Snippet;
11
13
  class?: string;
12
14
  ref?: HTMLButtonElement | HTMLAnchorElement;
@@ -261,7 +261,7 @@
261
261
  {#if renderSelected && selectedItem}
262
262
  {@render renderSelected(selectedItem)}
263
263
  {:else}
264
- <span>{selectedLabel}</span>
264
+ <span class="flex-1 min-w-0 truncate text-left">{selectedLabel}</span>
265
265
  {/if}
266
266
  <IIIcon iconName="caret-down" />
267
267
  </button>
@@ -331,7 +331,7 @@
331
331
  aria-haspopup="menu"
332
332
  aria-expanded={open}
333
333
  data-state={open ? 'open' : 'closed'}
334
- class={cn(children && triggerClass ? triggerClass : defaultTriggerClass)}
334
+ class={cn(children ? cn('[all:unset] cursor-default', triggerClass) : defaultTriggerClass)}
335
335
  onclick={toggle}
336
336
  >
337
337
  {#if children}
@@ -13,8 +13,12 @@
13
13
  titleAccessory?: Snippet
14
14
  footer?: Snippet
15
15
  showCloseButton?: boolean
16
- size?: 'sm' | 'md' | 'lg'
16
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
17
17
  overlay?: 'dark' | 'light' | 'none'
18
+ /** Cap the modal height (any CSS value, e.g. "60vh"). Defaults to 90vh. */
19
+ maxHeight?: string
20
+ /** Replace the body wrapper's padding/scroll defaults — e.g. for a full-height flex body. */
21
+ bodyClass?: string
18
22
  class?: string
19
23
  }
20
24
 
@@ -29,6 +33,8 @@
29
33
  showCloseButton = true,
30
34
  size = 'md',
31
35
  overlay = 'dark',
36
+ maxHeight,
37
+ bodyClass,
32
38
  class: className,
33
39
  }: Props = $props()
34
40
 
@@ -80,8 +86,11 @@
80
86
  size === 'sm' && 'max-w-400',
81
87
  size === 'md' && 'max-w-500',
82
88
  size === 'lg' && 'max-w-700',
89
+ size === 'xl' && 'max-w-[1100px]',
90
+ size === 'full' && 'max-w-[95vw] h-[90vh]',
83
91
  className
84
92
  )}
93
+ style={maxHeight ? `max-height: ${maxHeight}` : undefined}
85
94
  >
86
95
  <div class="flex items-start justify-between gap-12 px-24 pt-24 shrink-0">
87
96
  <div class="flex flex-col min-w-0 flex-1">
@@ -105,7 +114,7 @@
105
114
  </Dialog.Close>
106
115
  {/if}
107
116
  </div>
108
- <div class="px-24 py-20 flex-auto min-h-0 overflow-y-auto">
117
+ <div class={cn('flex-auto min-h-0', bodyClass ?? 'px-24 py-20 overflow-y-auto')}>
109
118
  {@render children()}
110
119
  </div>
111
120
  {#if footer}
@@ -8,8 +8,12 @@ type Props = {
8
8
  titleAccessory?: Snippet;
9
9
  footer?: Snippet;
10
10
  showCloseButton?: boolean;
11
- size?: 'sm' | 'md' | 'lg';
11
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
12
12
  overlay?: 'dark' | 'light' | 'none';
13
+ /** Cap the modal height (any CSS value, e.g. "60vh"). Defaults to 90vh. */
14
+ maxHeight?: string;
15
+ /** Replace the body wrapper's padding/scroll defaults — e.g. for a full-height flex body. */
16
+ bodyClass?: string;
13
17
  class?: string;
14
18
  };
15
19
  declare const IIModal: import("svelte").Component<Props, {}, "open">;
@@ -1,12 +1,15 @@
1
1
  <script lang="ts">
2
2
  import {cn} from '../utils/cn'
3
3
  import IIDropdownInput from '../IIDropdownInput/IIDropdownInput.svelte'
4
+ import IITooltip from '../IITooltip/IITooltip.svelte'
4
5
  import {useDensity} from '../density'
5
6
 
6
7
  type Tab = {
7
8
  value: string
8
9
  label: string
9
10
  count?: number
11
+ disabled?: boolean
12
+ tooltip?: string
10
13
  }
11
14
 
12
15
  type Props = {
@@ -55,6 +58,29 @@
55
58
  </script>
56
59
 
57
60
  <div bind:this={containerEl} class={cn('min-w-0 relative', className)}>
61
+ {#snippet pill(tab: Tab)}
62
+ <button
63
+ class={cn(
64
+ 'flex items-center rounded-control border-none outline-none cursor-default whitespace-nowrap',
65
+ densityClasses[density.value],
66
+ tab.disabled
67
+ ? 'bg-surface text-tertiary opacity-50 cursor-not-allowed'
68
+ : value === tab.value
69
+ ? 'bg-gray-100 text-gray-700'
70
+ : 'bg-surface text-secondary shadow-pill hover:bg-gray-100 hover:text-gray-700'
71
+ )}
72
+ style="transition: all var(--transition-fast)"
73
+ disabled={tab.disabled}
74
+ onclick={() => !tab.disabled && select(tab.value)}
75
+ tabindex={overflow ? -1 : 0}
76
+ >
77
+ {tab.label}
78
+ {#if tab.count != null}
79
+ <span class="ml-2 text-tiny opacity-70">({tab.count})</span>
80
+ {/if}
81
+ </button>
82
+ {/snippet}
83
+
58
84
  <!-- Hidden measure element — always rendered to detect when pills fit again -->
59
85
  <div
60
86
  bind:this={measureEl}
@@ -63,23 +89,13 @@
63
89
  style={overflow ? 'position: absolute; visibility: hidden; height: 0; overflow: hidden; pointer-events: none;' : ''}
64
90
  >
65
91
  {#each tabs as tab (tab.value)}
66
- <button
67
- class={cn(
68
- 'flex items-center rounded-control border-none outline-none cursor-default whitespace-nowrap',
69
- densityClasses[density.value],
70
- value === tab.value
71
- ? 'bg-gray-100 text-gray-700'
72
- : 'bg-surface text-secondary shadow-pill hover:bg-gray-100 hover:text-gray-700'
73
- )}
74
- style="transition: all var(--transition-fast)"
75
- onclick={() => select(tab.value)}
76
- tabindex={overflow ? -1 : 0}
77
- >
78
- {tab.label}
79
- {#if tab.count != null}
80
- <span class="ml-2 text-tiny opacity-70">({tab.count})</span>
81
- {/if}
82
- </button>
92
+ {#if tab.tooltip}
93
+ <IITooltip text={tab.tooltip} side="top" disabled={overflow}>
94
+ {@render pill(tab)}
95
+ </IITooltip>
96
+ {:else}
97
+ {@render pill(tab)}
98
+ {/if}
83
99
  {/each}
84
100
  </div>
85
101
 
@@ -2,6 +2,8 @@ type Tab = {
2
2
  value: string;
3
3
  label: string;
4
4
  count?: number;
5
+ disabled?: boolean;
6
+ tooltip?: string;
5
7
  };
6
8
  type Props = {
7
9
  tabs: Tab[];
@@ -16,10 +16,12 @@
16
16
  tabs: Tab[]
17
17
  value: string
18
18
  onChange: (value: string) => void
19
+ /** Stretch to fill the available width. Defaults to sizing to content. */
20
+ fullWidth?: boolean
19
21
  class?: string
20
22
  }
21
23
 
22
- let {tabs, value, onChange, class: className}: Props = $props()
24
+ let {tabs, value, onChange, fullWidth = false, class: className}: Props = $props()
23
25
 
24
26
  let listEl = $state<HTMLElement | null>(null)
25
27
  let overflowing = $state(false)
@@ -45,7 +47,11 @@
45
47
  }
46
48
  </script>
47
49
 
48
- <Tabs.Root {value} onValueChange={onChange} class={cn('relative w-full h-full', className)}>
50
+ <Tabs.Root
51
+ {value}
52
+ onValueChange={onChange}
53
+ class={cn('relative h-full', fullWidth ? 'w-full' : 'w-auto min-w-0 shrink', className)}
54
+ >
49
55
  <Tabs.List
50
56
  bind:ref={listEl}
51
57
  class={cn(
@@ -9,6 +9,8 @@ type Props = {
9
9
  tabs: Tab[];
10
10
  value: string;
11
11
  onChange: (value: string) => void;
12
+ /** Stretch to fill the available width. Defaults to sizing to content. */
13
+ fullWidth?: boolean;
12
14
  class?: string;
13
15
  };
14
16
  declare const IITabBar: import("svelte").Component<Props, {}, "">;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import {Tooltip as B} from 'bits-ui'
3
+ import {cn} from '../utils/cn'
4
+ import type {Snippet} from 'svelte'
5
+
6
+ type Side = 'top' | 'right' | 'bottom' | 'left'
7
+
8
+ type Props = {
9
+ text: string
10
+ side?: Side
11
+ /** Extra classes for the trigger wrapper (e.g. to size it as a flex child). */
12
+ class?: string
13
+ /** Render children in a plain wrapper with no tooltip (keeps layout identical). */
14
+ disabled?: boolean
15
+ /** Hover delay before the tooltip opens, in ms. */
16
+ delay?: number
17
+ children: Snippet
18
+ }
19
+
20
+ let {text, side = 'right', class: className, disabled = false, delay = 150, children}: Props = $props()
21
+ </script>
22
+
23
+ {#if disabled}
24
+ <span class={cn('inline-block', className)}>
25
+ {@render children()}
26
+ </span>
27
+ {:else}
28
+ <B.Provider delayDuration={delay}>
29
+ <B.Root>
30
+ <B.Trigger>
31
+ {#snippet child({props})}
32
+ <span {...props} class={cn('inline-block', className)}>
33
+ {@render children()}
34
+ </span>
35
+ {/snippet}
36
+ </B.Trigger>
37
+ <B.Portal>
38
+ <B.Content
39
+ {side}
40
+ sideOffset={6}
41
+ class="z-19 rounded-4 bg-gray-900 text-white text-tiny leading-tight font-medium px-8 py-4 shadow-dropdown data-[state=delayed-open]:animate-fade-in data-[state=instant-open]:animate-fade-in data-[state=closed]:animate-fade-out motion-reduce:animate-none"
42
+ >
43
+ {text}
44
+ </B.Content>
45
+ </B.Portal>
46
+ </B.Root>
47
+ </B.Provider>
48
+ {/if}
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ type Side = 'top' | 'right' | 'bottom' | 'left';
3
+ type Props = {
4
+ text: string;
5
+ side?: Side;
6
+ /** Extra classes for the trigger wrapper (e.g. to size it as a flex child). */
7
+ class?: string;
8
+ /** Render children in a plain wrapper with no tooltip (keeps layout identical). */
9
+ disabled?: boolean;
10
+ /** Hover delay before the tooltip opens, in ms. */
11
+ delay?: number;
12
+ children: Snippet;
13
+ };
14
+ declare const IITooltip: import("svelte").Component<Props, {}, "">;
15
+ type IITooltip = ReturnType<typeof IITooltip>;
16
+ export default IITooltip;
@@ -0,0 +1 @@
1
+ export { default as IITooltip } from './IITooltip.svelte';
@@ -0,0 +1 @@
1
+ export { default as IITooltip } from './IITooltip.svelte';
package/dist/index.d.ts CHANGED
@@ -42,6 +42,7 @@ export { IITaskCardSkeleton } from './IITaskCardSkeleton';
42
42
  export { IITextarea } from './IITextarea';
43
43
  export { IIToggle } from './IIToggle';
44
44
  export { IIToaster } from './IIToaster';
45
+ export { IITooltip } from './IITooltip';
45
46
  export { IIViewFilterChip } from './IIViewFilterChip';
46
47
  export type { AuditEvent, AuditFilter, Severity } from './IIAuditTrail';
47
48
  export type { BadgeVariant } from './IIBadge';
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ export { IITaskCardSkeleton } from './IITaskCardSkeleton';
46
46
  export { IITextarea } from './IITextarea';
47
47
  export { IIToggle } from './IIToggle';
48
48
  export { IIToaster } from './IIToaster';
49
+ export { IITooltip } from './IITooltip';
49
50
  export { IIViewFilterChip } from './IIViewFilterChip';
50
51
  // Utilities
51
52
  export { toast } from './toast';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@insymetri/styleguide",
3
- "version": "0.1.73",
3
+ "version": "0.1.74",
4
4
  "description": "Insymetri shared UI component library built with Svelte 5",
5
5
  "type": "module",
6
6
  "scripts": {