@juspay/svelte-ui-components 4.36.0 → 4.37.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.
@@ -21,6 +21,7 @@
21
21
  let {
22
22
  value = $bindable(''),
23
23
  layout = 'row',
24
+ variant = 'default',
24
25
  placeholder = '',
25
26
  disabled = false,
26
27
  textDisabled = null,
@@ -497,6 +498,7 @@
497
498
  <div
498
499
  class="chat-composer {classes ?? ''}"
499
500
  class:disabled
501
+ class:pill={variant === 'pill'}
500
502
  data-has-slash={slashCommands !== null ? '' : null}
501
503
  data-pw={typeof testId === 'string' ? testId : null}
502
504
  testID={typeof testId === 'string' ? testId : null}
@@ -623,6 +625,10 @@
623
625
  opacity: var(--chat-composer-disabled-opacity, 0.6);
624
626
  }
625
627
 
628
+ .chat-composer.pill {
629
+ border-radius: var(--chat-composer-pill-border-radius, 999px);
630
+ }
631
+
626
632
  /* .input below sets outline: none with nothing standing in for it, so the
627
633
  visible replacement lives here on the surrounding surface instead --
628
634
  :focus-within lights up whenever the textarea inside is focused, the same
@@ -5,6 +5,7 @@ export type OptionalChatComposerProperties = {
5
5
  value?: string;
6
6
  /** Text above a separate control row when stacked; row preserves the default. */
7
7
  layout?: 'row' | 'stacked';
8
+ variant?: 'default' | 'pill';
8
9
  placeholder?: string;
9
10
  disabled?: boolean;
10
11
  /**
@@ -0,0 +1,193 @@
1
+ <script lang="ts">
2
+ import Resizable from '../Resizable/Resizable.svelte';
3
+ import { registerDismissible } from '../_interaction/dismissal';
4
+ import type { ResizeSize } from '../Resizable/properties';
5
+ import type { DockPanelProperties, DockPanelSnapshot, DockPanelState } from './properties';
6
+
7
+ let {
8
+ state: panelState = $bindable('closed'),
9
+ width = $bindable(380),
10
+ minWidth = 300,
11
+ maxWidth = 600,
12
+ reservedWidth = $bindable(0),
13
+ label = 'Panel',
14
+ resizeLabel = 'Resize panel',
15
+ header,
16
+ body,
17
+ footer,
18
+ children,
19
+ testId,
20
+ classes,
21
+ onstatechange,
22
+ onwidthchange
23
+ }: DockPanelProperties = $props();
24
+
25
+ const lowerWidth = $derived(Number.isFinite(minWidth) ? Math.max(0, minWidth) : 300);
26
+ const upperWidth = $derived(
27
+ Number.isFinite(maxWidth) ? Math.max(lowerWidth, maxWidth) : Math.max(lowerWidth, 600)
28
+ );
29
+ const clampedWidth = $derived(
30
+ Math.min(upperWidth, Math.max(lowerWidth, Number.isFinite(width) ? width : 380))
31
+ );
32
+
33
+ const changeState = (nextState: DockPanelState): void => {
34
+ if (panelState !== nextState) {
35
+ panelState = nextState;
36
+ onstatechange?.(nextState);
37
+ }
38
+ };
39
+ const expand = (): void => changeState('expanded');
40
+ const collapse = (): void => changeState('docked');
41
+ const close = (): void => changeState('closed');
42
+
43
+ const handleResize = (size: ResizeSize): void => {
44
+ const nextWidth = Math.min(upperWidth, Math.max(lowerWidth, size.width));
45
+ if (width !== nextWidth) {
46
+ width = nextWidth;
47
+ onwidthchange?.(width);
48
+ }
49
+ };
50
+
51
+ const synchronizePanel = (node: HTMLElement, snapshot: DockPanelSnapshot) => {
52
+ let releaseDismissal: (() => void) | null = null;
53
+ const update = (nextSnapshot: DockPanelSnapshot): void => {
54
+ if (width !== nextSnapshot.width) {
55
+ width = nextSnapshot.width;
56
+ onwidthchange?.(width);
57
+ }
58
+ const nextReservation = nextSnapshot.state === 'docked' ? nextSnapshot.width : 0;
59
+ if (reservedWidth !== nextReservation) {
60
+ reservedWidth = nextReservation;
61
+ }
62
+ if (nextSnapshot.state === 'expanded' && releaseDismissal === null) {
63
+ releaseDismissal = registerDismissible({ element: () => node, onEscape: collapse });
64
+ } else if (nextSnapshot.state !== 'expanded' && releaseDismissal !== null) {
65
+ releaseDismissal();
66
+ releaseDismissal = null;
67
+ }
68
+ };
69
+ update(snapshot);
70
+ return { update, destroy: () => releaseDismissal?.() };
71
+ };
72
+ </script>
73
+
74
+ <div
75
+ class="dock-panel {classes ?? ''}"
76
+ class:closed={panelState === 'closed'}
77
+ class:expanded={panelState === 'expanded'}
78
+ data-state={panelState}
79
+ data-pw={typeof testId === 'string' ? testId : null}
80
+ testID={typeof testId === 'string' ? testId : null}
81
+ role="complementary"
82
+ aria-label={label}
83
+ inert={panelState === 'closed'}
84
+ use:synchronizePanel={{ state: panelState, width: clampedWidth }}
85
+ style:width={panelState === 'expanded' ? null : `${clampedWidth}px`}
86
+ >
87
+ <Resizable
88
+ width={panelState === 'docked' ? clampedWidth : null}
89
+ minWidth={lowerWidth}
90
+ maxWidth={upperWidth}
91
+ handles={panelState === 'docked' ? ['left'] : []}
92
+ handleLabel={resizeLabel}
93
+ onresize={handleResize}
94
+ classes="dock-panel-frame"
95
+ >
96
+ {#if typeof header === 'function'}
97
+ <div class="header">{@render header({ state: panelState, expand, collapse, close })}</div>
98
+ {/if}
99
+ <div class="body">
100
+ {#if typeof body === 'function'}
101
+ {@render body()}
102
+ {:else if typeof children === 'function'}
103
+ {@render children()}
104
+ {/if}
105
+ </div>
106
+ {#if typeof footer === 'function'}
107
+ <div class="footer">{@render footer()}</div>
108
+ {/if}
109
+ </Resizable>
110
+ </div>
111
+
112
+ <style>
113
+ .dock-panel {
114
+ box-sizing: border-box;
115
+ position: var(--dock-panel-position, fixed);
116
+ top: var(--dock-panel-top, 0px);
117
+ right: var(--dock-panel-right, 0px);
118
+ bottom: var(--dock-panel-bottom, 0px);
119
+ display: flex;
120
+ flex-direction: column;
121
+ min-width: 0;
122
+ z-index: var(--dock-panel-z-index, 30);
123
+ background: var(--dock-panel-background, #ffffff);
124
+ color: var(--dock-panel-color, #18181b);
125
+ border-radius: var(--dock-panel-border-radius, 0px);
126
+ box-shadow: var(--dock-panel-box-shadow, -4px 0 16px #00000012);
127
+ opacity: 1;
128
+ transform: translateX(0);
129
+ transition:
130
+ opacity
131
+ var(--dock-panel-transition-duration, var(--duration-base, var(--motion-duration, 200ms)))
132
+ var(--dock-panel-transition-easing, var(--ease-smooth-out, var(--motion-easing, ease-out))),
133
+ transform
134
+ var(--dock-panel-transition-duration, var(--duration-base, var(--motion-duration, 200ms)))
135
+ var(--dock-panel-transition-easing, var(--ease-smooth-out, var(--motion-easing, ease-out))),
136
+ display
137
+ var(--dock-panel-transition-duration, var(--duration-base, var(--motion-duration, 200ms)))
138
+ allow-discrete;
139
+ }
140
+
141
+ .dock-panel.closed {
142
+ display: none;
143
+ opacity: 0;
144
+ transform: translateX(var(--dock-panel-enter-distance, var(--distance-base, 8px)));
145
+ }
146
+
147
+ .dock-panel.expanded {
148
+ left: var(--dock-panel-left, 0px);
149
+ width: calc(100% - var(--dock-panel-left, 0px) - var(--dock-panel-right, 0px));
150
+ }
151
+
152
+ .dock-panel :global(.dock-panel-frame) {
153
+ display: flex;
154
+ flex-direction: column;
155
+ flex: 1;
156
+ min-height: 0;
157
+ min-width: 0;
158
+ border: var(--dock-panel-border, 1px solid #e4e4e7);
159
+ --resizable-transition: none;
160
+ }
161
+
162
+ .header {
163
+ flex-shrink: 0;
164
+ padding: var(--dock-panel-header-padding, 0px);
165
+ border-bottom: var(--dock-panel-header-border, none);
166
+ }
167
+
168
+ .body {
169
+ flex: 1;
170
+ min-height: 0;
171
+ overflow: auto;
172
+ padding: var(--dock-panel-body-padding, 0px);
173
+ }
174
+
175
+ .footer {
176
+ flex-shrink: 0;
177
+ padding: var(--dock-panel-footer-padding, 0px);
178
+ border-top: var(--dock-panel-footer-border, none);
179
+ }
180
+
181
+ @starting-style {
182
+ .dock-panel:not(.closed) {
183
+ opacity: 0;
184
+ transform: translateX(var(--dock-panel-enter-distance, var(--distance-base, 8px)));
185
+ }
186
+ }
187
+
188
+ @media (prefers-reduced-motion: reduce) {
189
+ .dock-panel {
190
+ transition: none;
191
+ }
192
+ }
193
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { DockPanelProperties } from './properties';
2
+ declare const DockPanel: import("svelte").Component<DockPanelProperties, {}, "state" | "width" | "reservedWidth">;
3
+ type DockPanel = ReturnType<typeof DockPanel>;
4
+ export default DockPanel;
@@ -0,0 +1,30 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type DockPanelState = 'closed' | 'docked' | 'expanded';
3
+ export type DockPanelControls = {
4
+ state: DockPanelState;
5
+ expand: () => void;
6
+ collapse: () => void;
7
+ close: () => void;
8
+ };
9
+ export type DockPanelSnapshot = {
10
+ state: DockPanelState;
11
+ width: number;
12
+ };
13
+ export type DockPanelProperties = {
14
+ state?: DockPanelState;
15
+ width?: number;
16
+ minWidth?: number;
17
+ maxWidth?: number;
18
+ /** Published layout reservation. Bind to observe; zero when closed or expanded. */
19
+ reservedWidth?: number;
20
+ label?: string;
21
+ resizeLabel?: string;
22
+ header?: Snippet<[DockPanelControls]>;
23
+ body?: Snippet;
24
+ footer?: Snippet;
25
+ children?: Snippet;
26
+ testId?: string;
27
+ classes?: string;
28
+ onstatechange?: (state: DockPanelState) => void;
29
+ onwidthchange?: (width: number) => void;
30
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -142,11 +142,11 @@
142
142
  let handled = false;
143
143
 
144
144
  if (dir.x !== 0 && (event.key === 'ArrowRight' || event.key === 'ArrowLeft')) {
145
- nextWidth = clampWidth(nextWidth + (event.key === 'ArrowRight' ? step : -step));
145
+ nextWidth = clampWidth(nextWidth + dir.x * (event.key === 'ArrowRight' ? step : -step));
146
146
  handled = true;
147
147
  }
148
148
  if (dir.y !== 0 && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
149
- nextHeight = clampHeight(nextHeight + (event.key === 'ArrowDown' ? step : -step));
149
+ nextHeight = clampHeight(nextHeight + dir.y * (event.key === 'ArrowDown' ? step : -step));
150
150
  handled = true;
151
151
  }
152
152
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export { default as ArmedButton } from './ArmedButton/ArmedButton.svelte';
2
2
  export { default as Modal } from './Modal/Modal.svelte';
3
+ export { default as DockPanel } from './DockPanel/DockPanel.svelte';
4
+ export type { DockPanelState, DockPanelControls, DockPanelProperties } from './DockPanel/properties';
3
5
  export { default as BrandLoader } from './BrandLoader/BrandLoader.svelte';
4
6
  export { default as Button } from './Button/Button.svelte';
5
7
  export { default as Input } from './Input/Input.svelte';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { default as ArmedButton } from './ArmedButton/ArmedButton.svelte';
2
2
  export { default as Modal } from './Modal/Modal.svelte';
3
+ export { default as DockPanel } from './DockPanel/DockPanel.svelte';
3
4
  export { default as BrandLoader } from './BrandLoader/BrandLoader.svelte';
4
5
  export { default as Button } from './Button/Button.svelte';
5
6
  export { default as Input } from './Input/Input.svelte';
@@ -169,6 +169,9 @@
169
169
  --chat-header-close-hover-background-color: #252535;
170
170
  --chat-header-expand-color: #9ca3af;
171
171
  --chat-header-expand-hover-background-color: #252535;
172
+ --dock-panel-background: #17171f;
173
+ --dock-panel-color: #e5e7eb;
174
+ --dock-panel-border: 1px solid #30303d;
172
175
 
173
176
  /* ChatMessageList */
174
177
  --chat-message-list-jump-background-color: #1e1e2e;
@@ -17,7 +17,7 @@
17
17
  * stylesheet is a crutch for the migration window, not a permanent override.
18
18
  */
19
19
 
20
- /* components whose new default is `block` (88) */
20
+ /* components whose new default is `block` (89) */
21
21
  sui-accordion { --sui-accordion-display: inline; }
22
22
  sui-area-chart { --sui-area-chart-display: inline; }
23
23
  sui-aspect-ratio { --sui-aspect-ratio-display: inline; }
@@ -47,6 +47,7 @@ sui-color-picker { --sui-color-picker-display: inline; }
47
47
  sui-combobox { --sui-combobox-display: inline; }
48
48
  sui-command-menu { --sui-command-menu-display: inline; }
49
49
  sui-context-menu { --sui-context-menu-display: inline; }
50
+ sui-dock-panel { --sui-dock-panel-display: inline; }
50
51
  sui-draggable { --sui-draggable-display: inline; }
51
52
  sui-dual-axis-bar-chart { --sui-dual-axis-bar-chart-display: inline; }
52
53
  sui-empty-state { --sui-empty-state-display: inline; }
@@ -174,6 +174,11 @@
174
174
  "property": "--sui-delta-indicator-display",
175
175
  "default": "inline-block"
176
176
  },
177
+ {
178
+ "tag": "sui-dock-panel",
179
+ "property": "--sui-dock-panel-display",
180
+ "default": "block"
181
+ },
177
182
  {
178
183
  "tag": "sui-draggable",
179
184
  "property": "--sui-draggable-display",