@juspay/svelte-ui-components 4.10.4 → 4.11.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.
@@ -1,11 +1,7 @@
1
1
  import { partyOf } from './roles';
2
+ import { prefersReducedMotion } from '../utils';
2
3
  const REVEAL_CHARS_PER_TICK = 2;
3
4
  const REVEAL_INTERVAL_MS = 22;
4
- function prefersReducedMotion() {
5
- return (typeof window !== 'undefined' &&
6
- typeof window.matchMedia === 'function' &&
7
- window.matchMedia('(prefers-reduced-motion: reduce)').matches);
8
- }
9
5
  let idCounter = 0;
10
6
  function defaultId() {
11
7
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
@@ -9,6 +9,9 @@
9
9
  dismissible = false,
10
10
  disabled = false,
11
11
  tone,
12
+ as,
13
+ ariaExpanded,
14
+ ariaPressed,
12
15
  testId,
13
16
  title,
14
17
  dismissIcon,
@@ -22,6 +25,26 @@
22
25
 
23
26
  let interactive = $derived(typeof onclick === 'function');
24
27
 
28
+ // A <button> may not contain another button, and a dismissible pill is inherently two
29
+ // controls. Rather than emit invalid markup, that combination degrades to the div root —
30
+ // the same graceful-degradation rule Card applies to `as="a"` with no `href`.
31
+ const isButtonRoot = $derived(as === 'button' && !dismissible);
32
+ const rootTag = $derived(isButtonRoot ? 'button' : 'div');
33
+
34
+ // The synthetic shim exists only because a <div> has no button semantics. A real button
35
+ // already has them, and adding role/tabindex/keydown on top would duplicate the platform's
36
+ // own activation — Enter would fire the handler twice.
37
+ const needsInteractiveShim = $derived(interactive && !isButtonRoot);
38
+
39
+ // aria-expanded / aria-pressed / aria-disabled describe a control's state, so they are
40
+ // meaningless on a plain label and are emitted only once the pill actually is one.
41
+ //
42
+ // Note this is deliberately NOT gated on `onclick`: a button root is a real, focusable
43
+ // control whether or not a handler was supplied, so `<Pill as="button" disabled />` alone
44
+ // still has to announce that it is disabled. Gating on the handler left it reachable by
45
+ // keyboard with nothing saying it was inert.
46
+ const exposesControlState = $derived(isButtonRoot || needsInteractiveShim);
47
+
25
48
  function handleClick(event: MouseEvent): void {
26
49
  if (disabled) {
27
50
  return;
@@ -50,16 +73,19 @@
50
73
  }
51
74
  </script>
52
75
 
53
- <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
54
- <div
76
+ <svelte:element
77
+ this={rootTag}
55
78
  {...attrs ?? {}}
56
79
  class="pill {pillToneClass(tone)} {classes ?? ''}"
57
80
  class:disabled
81
+ type={isButtonRoot ? 'button' : null}
58
82
  onclick={interactive ? handleClick : null}
59
- onkeydown={interactive ? handleKeydown : null}
60
- role={interactive ? 'button' : null}
61
- tabindex={interactive ? 0 : null}
62
- aria-disabled={interactive && disabled ? true : null}
83
+ onkeydown={needsInteractiveShim ? handleKeydown : null}
84
+ role={needsInteractiveShim ? 'button' : null}
85
+ tabindex={needsInteractiveShim ? 0 : null}
86
+ aria-disabled={exposesControlState && disabled ? true : null}
87
+ aria-expanded={exposesControlState && typeof ariaExpanded === 'boolean' ? ariaExpanded : null}
88
+ aria-pressed={exposesControlState && typeof ariaPressed === 'boolean' ? ariaPressed : null}
63
89
  data-pw={typeof testId === 'string' ? testId : null}
64
90
  title={title ?? null}
65
91
  testID={typeof testId === 'string' ? testId : null}
@@ -87,7 +113,7 @@
87
113
  </Button>
88
114
  </div>
89
115
  {/if}
90
- </div>
116
+ </svelte:element>
91
117
 
92
118
  <style>
93
119
  .pill {
@@ -120,15 +146,32 @@
120
146
  flex-shrink: var(--pill-flex-shrink);
121
147
  }
122
148
 
123
- .pill[role='button'] {
149
+ .pill[role='button'],
150
+ button.pill {
124
151
  cursor: var(--pill-cursor, pointer);
125
152
  }
126
153
 
127
- .pill[role='button']:focus-visible {
154
+ .pill[role='button']:focus-visible,
155
+ button.pill:focus-visible {
128
156
  outline: var(--pill-focus-outline, 2px solid currentColor);
129
157
  outline-offset: var(--pill-focus-outline-offset, 2px);
130
158
  }
131
159
 
160
+ /* A button root arrives with user-agent styling a div never had: a default margin, the
161
+ native control appearance, and its own font stack. Neutralise exactly those three and
162
+ nothing else, so `as="button"` is a semantics change and not a visual one.
163
+
164
+ Deliberately NOT `font: inherit` here: that shorthand also resets line-height, and this
165
+ rule outranks .pill on specificity, so it would silently override
166
+ `--pill-line-height` and make a button chip 5px taller than the identical div. Every
167
+ other typographic property is already owned by .pill and needs no restatement. */
168
+ button.pill {
169
+ margin: 0;
170
+ font-family: var(--pill-font-family, inherit);
171
+ appearance: none;
172
+ -webkit-appearance: none;
173
+ }
174
+
132
175
  /* Tone defaults — an internal --_pill-tone-* layer, mirroring how Button's
133
176
  variant classes set --_btn-*: a plain --pill-background/--pill-color
134
177
  (explicit, or via `classes`) always wins over the tone's default. */
@@ -11,6 +11,14 @@ export type MandatoryPillProperties = {
11
11
  * default — the same precedence Button's `variant` already uses relative to `--button-color`.
12
12
  */
13
13
  export type PillTone = 'accent' | 'ok' | 'warn' | 'danger' | 'muted';
14
+ /**
15
+ * Root element for the pill. `'div'` is the default and renders exactly as before —
16
+ * non-interactive, or carrying the synthetic `role="button"`/`tabindex`/keydown shim when
17
+ * an `onclick` is supplied. `'button'` renders a real `<button type="button">` instead, so
18
+ * a chip-shaped control gets native focus, activation and announcement rather than an
19
+ * imitation of them.
20
+ */
21
+ export type PillRootTag = 'div' | 'button';
14
22
  export type OptionalPillProperties = {
15
23
  dismissible?: boolean;
16
24
  disabled?: boolean;
@@ -20,6 +28,31 @@ export type OptionalPillProperties = {
20
28
  * variable set. See `PillTone` for the mapping and override precedence.
21
29
  */
22
30
  tone?: PillTone;
31
+ /**
32
+ * Root element. Defaults to `'div'`, which renders exactly as before this prop existed.
33
+ *
34
+ * `'button'` gives a chip real control semantics — native keyboard activation, focus and
35
+ * announcement — instead of the `role="button"`/`tabindex`/keydown shim a `<div>` needs.
36
+ * Reach for it when the chip is a disclosure or a toggle (see `ariaExpanded` /
37
+ * `ariaPressed`), which a shimmed div cannot express correctly.
38
+ *
39
+ * One combination cannot be honoured: a `<button>` may not contain another button, and a
40
+ * `dismissible` pill is inherently two controls. `as="button"` together with
41
+ * `dismissible` therefore falls back to the `div` root and its shim rather than emitting
42
+ * invalid markup — the same rule `Card` applies to `as="a"` with no `href`.
43
+ */
44
+ as?: PillRootTag;
45
+ /**
46
+ * Expanded state of a disclosure chip, rendered as `aria-expanded`. Applied only when the
47
+ * pill is interactive (a `button` root, or a `div` with `onclick`), since the attribute is
48
+ * meaningless on a plain label. Omitted by default.
49
+ */
50
+ ariaExpanded?: boolean;
51
+ /**
52
+ * Pressed state of a toggle chip, rendered as `aria-pressed`. Applied only when the pill
53
+ * is interactive, for the same reason as `ariaExpanded`. Omitted by default.
54
+ */
55
+ ariaPressed?: boolean;
23
56
  testId?: string;
24
57
  title?: string;
25
58
  dismissIcon?: Snippet;
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { onMount, onDestroy, untrack } from 'svelte';
3
+ import { prefersReducedMotion } from '../utils';
3
4
  import type { TypewriterTextProperties, TypewriterCharacterDelayRange } from './properties';
4
5
 
5
6
  let {
@@ -75,7 +76,34 @@
75
76
  return speed;
76
77
  };
77
78
 
79
+ // Disclose everything still pending at once. The whitespace count has to be rebuilt
80
+ // from the text itself because the per-character path that normally maintains it is
81
+ // skipped entirely, and a later continuation would otherwise resume from a count that
82
+ // never saw the revealed suffix.
83
+ const revealRemainingText = (): void => {
84
+ if (timeoutId !== null) {
85
+ clearTimeout(timeoutId);
86
+ timeoutId = null;
87
+ }
88
+ const hadRemainingText = currentIndex < text.length;
89
+ displayedText = text;
90
+ currentIndex = text.length;
91
+ revealedWordCount = countWhitespace(text);
92
+ if (hadRemainingText) {
93
+ onprogress?.({ index: currentIndex, total: text.length, displayedText });
94
+ }
95
+ };
96
+
78
97
  const typeNextCharacter = (): void => {
98
+ // Typing IS the animation here, so a reduced-motion request has to suppress the
99
+ // reveal itself rather than a transition around it: disclose the text instead.
100
+ // `ChatController` already bypasses its own drain loop on this setting, and the two
101
+ // reveal implementations have to answer it identically — a consumer composing this
102
+ // component through `Chat`'s `messageBody` snippet is running both at once.
103
+ if (prefersReducedMotion()) {
104
+ revealRemainingText();
105
+ return;
106
+ }
79
107
  if (currentIndex < text.length) {
80
108
  const revealedCharacter = text[currentIndex];
81
109
  const revealedCharacterIndex = currentIndex;
@@ -122,6 +150,7 @@
122
150
  if (currentIndex >= previousTextLength) {
123
151
  if (timeoutId !== null) {
124
152
  clearTimeout(timeoutId);
153
+ timeoutId = null;
125
154
  }
126
155
  typeNextCharacter();
127
156
  }
@@ -133,16 +162,7 @@
133
162
  // eslint-disable-next-line no-restricted-syntax
134
163
  $effect(() => {
135
164
  if (!isStreaming && text.length > 0) {
136
- if (timeoutId !== null) {
137
- clearTimeout(timeoutId);
138
- }
139
- const hadRemainingText = currentIndex < text.length;
140
- displayedText = text;
141
- currentIndex = text.length;
142
- revealedWordCount = countWhitespace(text);
143
- if (hadRemainingText) {
144
- onprogress?.({ index: currentIndex, total: text.length, displayedText });
145
- }
165
+ revealRemainingText();
146
166
  }
147
167
  });
148
168
 
package/dist/utils.d.ts CHANGED
@@ -25,6 +25,16 @@ export declare function hsvToHsl(h: number, s: number, v: number): Hsl;
25
25
  export declare function hslToHsv(hDeg: number, sPct: number, lPct: number): Hsv;
26
26
  export declare function isValidHex(hex: string): boolean;
27
27
  export declare function clampInt(v: string, min: number, max: number): number;
28
+ /**
29
+ * Whether the user has asked the OS to minimise animation.
30
+ *
31
+ * Shared rather than per-component: two independent character-reveal
32
+ * implementations ship in this library — `ChatController`'s buffered drain and
33
+ * `TypewriterText`'s typing loop — and a reveal that honours this setting in one
34
+ * but not the other means the same OS preference silences an animation in a chat
35
+ * bubble and leaves it running in the message body rendered inside it.
36
+ */
37
+ export declare function prefersReducedMotion(): boolean;
28
38
  export declare function createDebouncer(delay: number): <T extends unknown[]>(callback: (...args: T) => void, ...args: T) => void;
29
39
  export declare function lockBodyScroll(): void;
30
40
  export declare function unlockBodyScroll(): void;
package/dist/utils.js CHANGED
@@ -282,6 +282,20 @@ export function clampInt(v, min, max) {
282
282
  return Math.max(min, Math.min(max, n));
283
283
  }
284
284
  // ── Misc ────────────────────────────────────────────────────────
285
+ /**
286
+ * Whether the user has asked the OS to minimise animation.
287
+ *
288
+ * Shared rather than per-component: two independent character-reveal
289
+ * implementations ship in this library — `ChatController`'s buffered drain and
290
+ * `TypewriterText`'s typing loop — and a reveal that honours this setting in one
291
+ * but not the other means the same OS preference silences an animation in a chat
292
+ * bubble and leaves it running in the message body rendered inside it.
293
+ */
294
+ export function prefersReducedMotion() {
295
+ return (typeof window !== 'undefined' &&
296
+ typeof window.matchMedia === 'function' &&
297
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches);
298
+ }
285
299
  export function createDebouncer(delay) {
286
300
  let lastCallTime = 0;
287
301
  return function (callback, ...args) {
package/dist-wc/index.js CHANGED
@@ -6125,6 +6125,9 @@ function clampInt(e, t, n) {
6125
6125
  let i = parseInt(e, 10);
6126
6126
  return Number.isNaN(i) ? t : Math.max(t, Math.min(n, i));
6127
6127
  }
6128
+ function prefersReducedMotion() {
6129
+ return typeof window < "u" && typeof window.matchMedia == "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
6130
+ }
6128
6131
  function createDebouncer(e) {
6129
6132
  let t = 0;
6130
6133
  return function(n, ...i) {
@@ -6766,23 +6769,23 @@ function pillToneClass(e) {
6766
6769
  }
6767
6770
  //#endregion
6768
6771
  //#region src/lib/Pill/Pill.svelte
6769
- var root$75 = /* @__PURE__ */ from_html("<span class=\"pill-leading-icon svelte-13eug5u\"><!></span>"), root_1$64 = /* @__PURE__ */ from_html("<div class=\"pill-dismiss svelte-13eug5u\"><!></div>"), root_2$48 = /* @__PURE__ */ from_html("<div><!> <span class=\"pill-text svelte-13eug5u\"> </span> <!></div>"), $$css$75 = {
6772
+ var root$75 = /* @__PURE__ */ from_html("<span class=\"pill-leading-icon svelte-13eug5u\"><!></span>"), root_1$64 = /* @__PURE__ */ from_html("<div class=\"pill-dismiss svelte-13eug5u\"><!></div>"), root_2$48 = /* @__PURE__ */ from_html("<!> <span class=\"pill-text svelte-13eug5u\"> </span> <!>", 1), $$css$75 = {
6770
6773
  hash: "svelte-13eug5u",
6771
- code: ".pill.svelte-13eug5u {display:inline-flex;align-items:center;\n /* A pill is content-width by default. A caller stacking pills into a menu needs\n them to fill the column and align their labels left, which is a layout choice\n the call site owns — hence tokens rather than a variant. */width:var(--pill-width, auto);justify-content:var(--pill-justify-content, center);text-align:var(--pill-text-align, center);gap:var(--pill-gap, 4px);background-color:var(--pill-background, var(--_pill-tone-background, #e0e0e0));color:var(--pill-color, var(--_pill-tone-color, #333333));font-size:var(--pill-font-size, 13px);font-weight:var(--pill-font-weight, 500);font-family:var(--pill-font-family);letter-spacing:var(--pill-letter-spacing, normal);text-transform:var(--pill-text-transform, none);padding:var(--pill-padding, 6px 10px);border-radius:var(--pill-border-radius, 999px);border:var(--pill-border, none);\n /* Non-interactive by default: nothing is clickable, so nothing should look\n clickable. The pointer default below applies only once role=\"button\" is\n actually present (see handleClick / `interactive`) — an explicit\n --pill-cursor still wins in both cases. */cursor:var(--pill-cursor, default);max-width:var(--pill-max-width);line-height:var(--pill-line-height, 1);flex-shrink:var(--pill-flex-shrink);}.pill[role='button'].svelte-13eug5u {cursor:var(--pill-cursor, pointer);}.pill[role='button'].svelte-13eug5u:focus-visible {outline:var(--pill-focus-outline, 2px solid currentColor);outline-offset:var(--pill-focus-outline-offset, 2px);}\n\n /* Tone defaults — an internal --_pill-tone-* layer, mirroring how Button's\n variant classes set --_btn-*: a plain --pill-background/--pill-color\n (explicit, or via `classes`) always wins over the tone's default. */.tone-accent.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-accent-background, #d1ecf1);--_pill-tone-color: var(--pill-tone-accent-color, #0c5460);}.tone-ok.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-ok-background, #d4edda);--_pill-tone-color: var(--pill-tone-ok-color, #155724);}.tone-warn.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-warn-background, #fff3cd);--_pill-tone-color: var(--pill-tone-warn-color, #856404);}.tone-danger.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-danger-background, #f8d7da);--_pill-tone-color: var(--pill-tone-danger-color, #721c24);}.tone-muted.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-muted-background, #f1f1f1);--_pill-tone-color: var(--pill-tone-muted-color, #6b7280);}.pill.svelte-13eug5u:hover:not(.disabled) {background-color:var(\n --pill-hover-background,\n var(--pill-background, var(--_pill-tone-background, #d0d0d0))\n );color:var(--pill-hover-color, var(--pill-color, var(--_pill-tone-color, #333333)));}.pill.disabled.svelte-13eug5u {opacity:var(--pill-disabled-opacity, 0.4);cursor:var(--pill-disabled-cursor, not-allowed);}.pill-text.svelte-13eug5u {overflow:hidden;text-overflow:var(--pill-text-overflow, ellipsis);white-space:var(--pill-text-white-space, nowrap);}.pill-leading-icon.svelte-13eug5u {display:inline-flex;align-items:center;flex-shrink:0;}.pill-dismiss.svelte-13eug5u {--button-color: transparent;--button-border: none;--button-padding: 0;--button-text-color: var(--pill-dismiss-color, currentColor);--button-hover-color: transparent;--button-hover-text-color: var(\n --pill-dismiss-hover-color,\n var(--pill-dismiss-color, currentColor)\n );--cursor: inherit;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;}\n\n /* Consumer themes can set Button tokens on its container, beating inherited\n wrapper values. Pin the painting element too so the chip owns its enabled\n glyph; leave disabled colours and focus indicators to the consumer theme. */.pill-dismiss.svelte-13eug5u .button-container,\n .pill-dismiss.svelte-13eug5u .button-el {--button-color: transparent;--button-background: none;--button-active-background: transparent;--button-border: none;--button-padding: 0;--button-text-color: var(--pill-dismiss-color, currentColor);--button-hover-color: transparent;--button-hover-border: none;--button-hover-text-color: var(\n --pill-dismiss-hover-color,\n var(--pill-dismiss-color, currentColor)\n );}.pill-dismiss.svelte-13eug5u svg {width:var(--pill-dismiss-size, 14px);height:var(--pill-dismiss-size, 14px);}"
6774
+ code: ".pill.svelte-13eug5u {display:inline-flex;align-items:center;\n /* A pill is content-width by default. A caller stacking pills into a menu needs\n them to fill the column and align their labels left, which is a layout choice\n the call site owns — hence tokens rather than a variant. */width:var(--pill-width, auto);justify-content:var(--pill-justify-content, center);text-align:var(--pill-text-align, center);gap:var(--pill-gap, 4px);background-color:var(--pill-background, var(--_pill-tone-background, #e0e0e0));color:var(--pill-color, var(--_pill-tone-color, #333333));font-size:var(--pill-font-size, 13px);font-weight:var(--pill-font-weight, 500);font-family:var(--pill-font-family);letter-spacing:var(--pill-letter-spacing, normal);text-transform:var(--pill-text-transform, none);padding:var(--pill-padding, 6px 10px);border-radius:var(--pill-border-radius, 999px);border:var(--pill-border, none);\n /* Non-interactive by default: nothing is clickable, so nothing should look\n clickable. The pointer default below applies only once role=\"button\" is\n actually present (see handleClick / `interactive`) — an explicit\n --pill-cursor still wins in both cases. */cursor:var(--pill-cursor, default);max-width:var(--pill-max-width);line-height:var(--pill-line-height, 1);flex-shrink:var(--pill-flex-shrink);}.pill[role='button'].svelte-13eug5u,\n button.pill.svelte-13eug5u {cursor:var(--pill-cursor, pointer);}.pill[role='button'].svelte-13eug5u:focus-visible,\n button.pill.svelte-13eug5u:focus-visible {outline:var(--pill-focus-outline, 2px solid currentColor);outline-offset:var(--pill-focus-outline-offset, 2px);}\n\n /* A button root arrives with user-agent styling a div never had: a default margin, the\n native control appearance, and its own font stack. Neutralise exactly those three and\n nothing else, so `as=\"button\"` is a semantics change and not a visual one.\n\n Deliberately NOT `font: inherit` here: that shorthand also resets line-height, and this\n rule outranks .pill on specificity, so it would silently override\n `--pill-line-height` and make a button chip 5px taller than the identical div. Every\n other typographic property is already owned by .pill and needs no restatement. */button.pill.svelte-13eug5u {margin:0;font-family:var(--pill-font-family, inherit);appearance:none;-webkit-appearance:none;}\n\n /* Tone defaults — an internal --_pill-tone-* layer, mirroring how Button's\n variant classes set --_btn-*: a plain --pill-background/--pill-color\n (explicit, or via `classes`) always wins over the tone's default. */.tone-accent.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-accent-background, #d1ecf1);--_pill-tone-color: var(--pill-tone-accent-color, #0c5460);}.tone-ok.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-ok-background, #d4edda);--_pill-tone-color: var(--pill-tone-ok-color, #155724);}.tone-warn.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-warn-background, #fff3cd);--_pill-tone-color: var(--pill-tone-warn-color, #856404);}.tone-danger.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-danger-background, #f8d7da);--_pill-tone-color: var(--pill-tone-danger-color, #721c24);}.tone-muted.svelte-13eug5u {--_pill-tone-background: var(--pill-tone-muted-background, #f1f1f1);--_pill-tone-color: var(--pill-tone-muted-color, #6b7280);}.pill.svelte-13eug5u:hover:not(.disabled) {background-color:var(\n --pill-hover-background,\n var(--pill-background, var(--_pill-tone-background, #d0d0d0))\n );color:var(--pill-hover-color, var(--pill-color, var(--_pill-tone-color, #333333)));}.pill.disabled.svelte-13eug5u {opacity:var(--pill-disabled-opacity, 0.4);cursor:var(--pill-disabled-cursor, not-allowed);}.pill-text.svelte-13eug5u {overflow:hidden;text-overflow:var(--pill-text-overflow, ellipsis);white-space:var(--pill-text-white-space, nowrap);}.pill-leading-icon.svelte-13eug5u {display:inline-flex;align-items:center;flex-shrink:0;}.pill-dismiss.svelte-13eug5u {--button-color: transparent;--button-border: none;--button-padding: 0;--button-text-color: var(--pill-dismiss-color, currentColor);--button-hover-color: transparent;--button-hover-text-color: var(\n --pill-dismiss-hover-color,\n var(--pill-dismiss-color, currentColor)\n );--cursor: inherit;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;}\n\n /* Consumer themes can set Button tokens on its container, beating inherited\n wrapper values. Pin the painting element too so the chip owns its enabled\n glyph; leave disabled colours and focus indicators to the consumer theme. */.pill-dismiss.svelte-13eug5u .button-container,\n .pill-dismiss.svelte-13eug5u .button-el {--button-color: transparent;--button-background: none;--button-active-background: transparent;--button-border: none;--button-padding: 0;--button-text-color: var(--pill-dismiss-color, currentColor);--button-hover-color: transparent;--button-hover-border: none;--button-hover-text-color: var(\n --pill-dismiss-hover-color,\n var(--pill-dismiss-color, currentColor)\n );}.pill-dismiss.svelte-13eug5u svg {width:var(--pill-dismiss-size, 14px);height:var(--pill-dismiss-size, 14px);}"
6772
6775
  };
6773
6776
  function Pill(e, t) {
6774
6777
  push(t, !0), append_styles$1(e, $$css$75);
6775
- let n = prop(t, "text", 7), i = prop(t, "dismissible", 7, !1), a = prop(t, "disabled", 7, !1), o = prop(t, "tone", 7), s = prop(t, "testId", 7), c = prop(t, "title", 7), l = prop(t, "dismissIcon", 7), u = prop(t, "dismissLabel", 7), f = prop(t, "leadingIcon", 7), p = prop(t, "onclick", 7), h = prop(t, "ondismiss", 7), S = prop(t, "classes", 7), C = prop(t, "attrs", 7), k = /* @__PURE__ */ user_derived(() => typeof p() == "function");
6776
- function R(e) {
6777
- a() || p()?.(e);
6778
+ let n = prop(t, "text", 7), i = prop(t, "dismissible", 7, !1), a = prop(t, "disabled", 7, !1), o = prop(t, "tone", 7), s = prop(t, "as", 7), c = prop(t, "ariaExpanded", 7), l = prop(t, "ariaPressed", 7), u = prop(t, "testId", 7), f = prop(t, "title", 7), p = prop(t, "dismissIcon", 7), h = prop(t, "dismissLabel", 7), S = prop(t, "leadingIcon", 7), C = prop(t, "onclick", 7), k = prop(t, "ondismiss", 7), R = prop(t, "classes", 7), G = prop(t, "attrs", 7), te = /* @__PURE__ */ user_derived(() => typeof C() == "function"), ne = /* @__PURE__ */ user_derived(() => s() === "button" && !i()), re = /* @__PURE__ */ user_derived(() => get(ne) ? "button" : "div"), be = /* @__PURE__ */ user_derived(() => get(te) && !get(ne)), Me = /* @__PURE__ */ user_derived(() => get(ne) || get(be));
6779
+ function Re(e) {
6780
+ a() || C()?.(e);
6778
6781
  }
6779
- function G(e) {
6782
+ function Ue(e) {
6780
6783
  e.target === e.currentTarget && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), e.currentTarget instanceof HTMLElement && e.currentTarget.click());
6781
6784
  }
6782
- function te(e) {
6783
- e.stopPropagation(), !a() && h()?.();
6785
+ function it(e) {
6786
+ e.stopPropagation(), !a() && k()?.();
6784
6787
  }
6785
- var ne = {
6788
+ var at = {
6786
6789
  get text() {
6787
6790
  return n();
6788
6791
  },
@@ -6807,123 +6810,149 @@ function Pill(e, t) {
6807
6810
  set tone(e) {
6808
6811
  o(e), flushSync();
6809
6812
  },
6810
- get testId() {
6813
+ get as() {
6811
6814
  return s();
6812
6815
  },
6813
- set testId(e) {
6816
+ set as(e) {
6814
6817
  s(e), flushSync();
6815
6818
  },
6816
- get title() {
6819
+ get ariaExpanded() {
6817
6820
  return c();
6818
6821
  },
6819
- set title(e) {
6822
+ set ariaExpanded(e) {
6820
6823
  c(e), flushSync();
6821
6824
  },
6822
- get dismissIcon() {
6825
+ get ariaPressed() {
6823
6826
  return l();
6824
6827
  },
6825
- set dismissIcon(e) {
6828
+ set ariaPressed(e) {
6826
6829
  l(e), flushSync();
6827
6830
  },
6828
- get dismissLabel() {
6831
+ get testId() {
6829
6832
  return u();
6830
6833
  },
6831
- set dismissLabel(e) {
6834
+ set testId(e) {
6832
6835
  u(e), flushSync();
6833
6836
  },
6834
- get leadingIcon() {
6837
+ get title() {
6835
6838
  return f();
6836
6839
  },
6837
- set leadingIcon(e) {
6840
+ set title(e) {
6838
6841
  f(e), flushSync();
6839
6842
  },
6840
- get onclick() {
6843
+ get dismissIcon() {
6841
6844
  return p();
6842
6845
  },
6843
- set onclick(e) {
6846
+ set dismissIcon(e) {
6844
6847
  p(e), flushSync();
6845
6848
  },
6846
- get ondismiss() {
6849
+ get dismissLabel() {
6847
6850
  return h();
6848
6851
  },
6849
- set ondismiss(e) {
6852
+ set dismissLabel(e) {
6850
6853
  h(e), flushSync();
6851
6854
  },
6852
- get classes() {
6855
+ get leadingIcon() {
6853
6856
  return S();
6854
6857
  },
6855
- set classes(e) {
6858
+ set leadingIcon(e) {
6856
6859
  S(e), flushSync();
6857
6860
  },
6858
- get attrs() {
6861
+ get onclick() {
6859
6862
  return C();
6860
6863
  },
6861
- set attrs(e) {
6864
+ set onclick(e) {
6862
6865
  C(e), flushSync();
6866
+ },
6867
+ get ondismiss() {
6868
+ return k();
6869
+ },
6870
+ set ondismiss(e) {
6871
+ k(e), flushSync();
6872
+ },
6873
+ get classes() {
6874
+ return R();
6875
+ },
6876
+ set classes(e) {
6877
+ R(e), flushSync();
6878
+ },
6879
+ get attrs() {
6880
+ return G();
6881
+ },
6882
+ set attrs(e) {
6883
+ G(e), flushSync();
6863
6884
  }
6864
- }, re = root_2$48();
6865
- attribute_effect(re, (e) => ({
6866
- ...C() ?? {},
6867
- class: `pill ${e ?? ""} ${S() ?? "" ?? ""}`,
6868
- onclick: get(k) ? R : null,
6869
- onkeydown: get(k) ? G : null,
6870
- role: get(k) ? "button" : null,
6871
- tabindex: get(k) ? 0 : null,
6872
- "aria-disabled": get(k) && a() ? !0 : null,
6873
- "data-pw": typeof s() == "string" ? s() : null,
6874
- title: c() ?? null,
6875
- testID: typeof s() == "string" ? s() : null,
6876
- [CLASS]: { disabled: a() }
6877
- }), [() => pillToneClass(o())], void 0, void 0, "svelte-13eug5u");
6878
- var be = child(re), Me = (e) => {
6879
- var t = root$75();
6880
- snippet(child(t), f), reset(t), append(e, t);
6881
- };
6882
- if_block(be, (e) => {
6883
- typeof f() == "function" && e(Me);
6884
- });
6885
- var Re = sibling(be, 2), Ue = child(Re, !0);
6886
- reset(Re);
6887
- var it = sibling(Re, 2), at = (e) => {
6888
- var t = root_1$64(), n = child(t);
6889
- {
6890
- let e = /* @__PURE__ */ user_derived(() => u()?.trim() || "Dismiss");
6891
- Button(n, spread_props({
6892
- variant: "ghost",
6893
- get disabled() {
6894
- return a();
6895
- },
6896
- onclick: te,
6897
- get ariaLabel() {
6898
- return get(e);
6899
- }
6900
- }, () => typeof s() == "string" ? { testId: `${s()}-dismiss` } : {}, {
6901
- children: (e, t) => {
6902
- var n = comment(), i = first_child(n), a = (e) => {
6903
- var t = comment();
6904
- snippet(first_child(t), l), append(e, t);
6905
- }, o = (e) => {
6906
- var t = comment();
6907
- html(first_child(t), () => close_default), append(e, t);
6908
- };
6909
- if_block(i, (e) => {
6910
- typeof l() == "function" ? e(a) : e(o, -1);
6911
- }), append(e, n);
6912
- },
6913
- $$slots: { default: !0 }
6914
- }));
6915
- }
6916
- reset(t), append(e, t);
6917
- };
6918
- return if_block(it, (e) => {
6919
- i() && e(at);
6920
- }), reset(re), template_effect(() => set_text(Ue, n())), append(e, re), pop(ne);
6885
+ }, ot = comment();
6886
+ return element(first_child(ot), () => get(re), !1, (e, t) => {
6887
+ attribute_effect(e, (e) => ({
6888
+ ...G() ?? {},
6889
+ class: `pill ${e ?? ""} ${R() ?? "" ?? ""}`,
6890
+ type: get(ne) ? "button" : null,
6891
+ onclick: get(te) ? Re : null,
6892
+ onkeydown: get(be) ? Ue : null,
6893
+ role: get(be) ? "button" : null,
6894
+ tabindex: get(be) ? 0 : null,
6895
+ "aria-disabled": get(Me) && a() ? !0 : null,
6896
+ "aria-expanded": get(Me) && typeof c() == "boolean" ? c() : null,
6897
+ "aria-pressed": get(Me) && typeof l() == "boolean" ? l() : null,
6898
+ "data-pw": typeof u() == "string" ? u() : null,
6899
+ title: f() ?? null,
6900
+ testID: typeof u() == "string" ? u() : null,
6901
+ [CLASS]: { disabled: a() }
6902
+ }), [() => pillToneClass(o())], void 0, void 0, "svelte-13eug5u");
6903
+ var s = root_2$48(), C = first_child(s), k = (e) => {
6904
+ var t = root$75();
6905
+ snippet(child(t), S), reset(t), append(e, t);
6906
+ };
6907
+ if_block(C, (e) => {
6908
+ typeof S() == "function" && e(k);
6909
+ });
6910
+ var re = sibling(C, 2), at = child(re, !0);
6911
+ reset(re);
6912
+ var ot = sibling(re, 2), ct = (e) => {
6913
+ var t = root_1$64(), n = child(t);
6914
+ {
6915
+ let e = /* @__PURE__ */ user_derived(() => h()?.trim() || "Dismiss");
6916
+ Button(n, spread_props({
6917
+ variant: "ghost",
6918
+ get disabled() {
6919
+ return a();
6920
+ },
6921
+ onclick: it,
6922
+ get ariaLabel() {
6923
+ return get(e);
6924
+ }
6925
+ }, () => typeof u() == "string" ? { testId: `${u()}-dismiss` } : {}, {
6926
+ children: (e, t) => {
6927
+ var n = comment(), i = first_child(n), a = (e) => {
6928
+ var t = comment();
6929
+ snippet(first_child(t), p), append(e, t);
6930
+ }, o = (e) => {
6931
+ var t = comment();
6932
+ html(first_child(t), () => close_default), append(e, t);
6933
+ };
6934
+ if_block(i, (e) => {
6935
+ typeof p() == "function" ? e(a) : e(o, -1);
6936
+ }), append(e, n);
6937
+ },
6938
+ $$slots: { default: !0 }
6939
+ }));
6940
+ }
6941
+ reset(t), append(e, t);
6942
+ };
6943
+ if_block(ot, (e) => {
6944
+ i() && e(ct);
6945
+ }), template_effect(() => set_text(at, n())), append(t, s);
6946
+ }), append(e, ot), pop(at);
6921
6947
  }
6922
6948
  create_custom_element(Pill, {
6923
6949
  text: {},
6924
6950
  dismissible: {},
6925
6951
  disabled: {},
6926
6952
  tone: {},
6953
+ as: {},
6954
+ ariaExpanded: {},
6955
+ ariaPressed: {},
6927
6956
  testId: {},
6928
6957
  title: {},
6929
6958
  dismissIcon: {},
@@ -10286,15 +10315,23 @@ var rest_excludes$62 = new Set([
10286
10315
  "$$events",
10287
10316
  "$$legacy",
10288
10317
  "$$host",
10289
- "pillTitle"
10318
+ "pillTitle",
10319
+ "pillAriaExpanded",
10320
+ "pillAriaPressed"
10290
10321
  ]);
10291
10322
  function Pill_wc(e, t) {
10292
10323
  push(t, !0);
10293
- let n = prop(t, "pillTitle", 7), i = /* @__PURE__ */ rest_props(t, rest_excludes$62);
10294
- return Pill(e, spread_props(() => i, {
10324
+ let n = prop(t, "pillTitle", 7), i = prop(t, "pillAriaExpanded", 7), a = prop(t, "pillAriaPressed", 7), o = /* @__PURE__ */ rest_props(t, rest_excludes$62);
10325
+ return Pill(e, spread_props(() => o, {
10295
10326
  get title() {
10296
10327
  return n();
10297
10328
  },
10329
+ get ariaExpanded() {
10330
+ return i();
10331
+ },
10332
+ get ariaPressed() {
10333
+ return a();
10334
+ },
10298
10335
  leadingIcon: (e) => {
10299
10336
  var n = comment();
10300
10337
  slot(first_child(n), t, "leading-icon", {}, null), append(e, n);
@@ -10316,6 +10353,18 @@ function Pill_wc(e, t) {
10316
10353
  },
10317
10354
  set pillTitle(e) {
10318
10355
  n(e), flushSync();
10356
+ },
10357
+ get pillAriaExpanded() {
10358
+ return i();
10359
+ },
10360
+ set pillAriaExpanded(e) {
10361
+ i(e), flushSync();
10362
+ },
10363
+ get pillAriaPressed() {
10364
+ return a();
10365
+ },
10366
+ set pillAriaPressed(e) {
10367
+ a(e), flushSync();
10319
10368
  }
10320
10369
  });
10321
10370
  }
@@ -10336,6 +10385,19 @@ customElements.define("sui-pill", create_custom_element(Pill_wc, {
10336
10385
  attribute: "tone",
10337
10386
  type: "String"
10338
10387
  },
10388
+ as: {
10389
+ attribute: "as",
10390
+ reflect: !0,
10391
+ type: "String"
10392
+ },
10393
+ pillAriaExpanded: {
10394
+ attribute: "aria-expanded",
10395
+ type: "Boolean"
10396
+ },
10397
+ pillAriaPressed: {
10398
+ attribute: "aria-pressed",
10399
+ type: "Boolean"
10400
+ },
10339
10401
  testId: {
10340
10402
  attribute: "test-id",
10341
10403
  type: "String"
@@ -32398,36 +32460,40 @@ function TypewriterText(e, t) {
32398
32460
  index: t,
32399
32461
  wordCount: get(R)
32400
32462
  }) : s() ? re.test(e) && s().digit ? be(s().digit) : G.has(e) && s().whitespace ? be(s().whitespace) : ne.has(e) && s().punctuation ? be(s().punctuation) : s().default ? be(s().default) : i() : i(), Re = () => {
32463
+ get(C) !== null && (clearTimeout(get(C)), set(C, null));
32464
+ let e = get(S) < n().length;
32465
+ set(h, n(), !0), set(S, n().length, !0), set(R, te(n()), !0), e && l()?.({
32466
+ index: get(S),
32467
+ total: n().length,
32468
+ displayedText: get(h)
32469
+ });
32470
+ }, Ue = () => {
32471
+ if (prefersReducedMotion()) {
32472
+ Re();
32473
+ return;
32474
+ }
32401
32475
  if (get(S) < n().length) {
32402
32476
  let e = n()[get(S)], t = get(S);
32403
32477
  G.has(e) && update(R), set(h, n().substring(0, get(S) + 1), !0), update(S), l()?.({
32404
32478
  index: get(S),
32405
32479
  total: n().length,
32406
32480
  displayedText: get(h)
32407
- }), set(C, setTimeout(Re, Me(e, t)), !0);
32481
+ }), set(C, setTimeout(Ue, Me(e, t)), !0);
32408
32482
  }
32409
32483
  };
32410
32484
  user_effect(() => {
32411
32485
  let e = n();
32412
32486
  untrack(() => {
32413
- e.length >= get(k) && e.startsWith(get(h)) || (get(C) !== null && (clearTimeout(get(C)), set(C, null)), set(h, ""), set(S, 0), set(k, 0), set(R, 0)), e.length > 0 && e.length > get(k) && (get(S) >= get(k) && (get(C) !== null && clearTimeout(get(C)), Re()), set(k, e.length, !0));
32487
+ e.length >= get(k) && e.startsWith(get(h)) || (get(C) !== null && (clearTimeout(get(C)), set(C, null)), set(h, ""), set(S, 0), set(k, 0), set(R, 0)), e.length > 0 && e.length > get(k) && (get(S) >= get(k) && (get(C) !== null && (clearTimeout(get(C)), set(C, null)), Ue()), set(k, e.length, !0));
32414
32488
  });
32415
32489
  }), user_effect(() => {
32416
- if (!a() && n().length > 0) {
32417
- get(C) !== null && clearTimeout(get(C));
32418
- let e = get(S) < n().length;
32419
- set(h, n(), !0), set(S, n().length, !0), set(R, te(n()), !0), e && l()?.({
32420
- index: get(S),
32421
- total: n().length,
32422
- displayedText: get(h)
32423
- });
32424
- }
32490
+ !a() && n().length > 0 && Re();
32425
32491
  }), onMount(() => {
32426
- n().length > 0 && (set(k, n().length, !0), Re());
32492
+ n().length > 0 && (set(k, n().length, !0), Ue());
32427
32493
  }), onDestroy(() => {
32428
32494
  get(C) !== null && clearTimeout(get(C));
32429
32495
  });
32430
- var Ue = {
32496
+ var it = {
32431
32497
  get text() {
32432
32498
  return n();
32433
32499
  },
@@ -32488,12 +32554,12 @@ function TypewriterText(e, t) {
32488
32554
  set classes(e) {
32489
32555
  p(e), flushSync();
32490
32556
  }
32491
- }, it = root$12();
32492
- let at;
32493
- var ot = child(it), ct = (e) => {
32557
+ }, at = root$12();
32558
+ let ot;
32559
+ var ct = child(at), lt = (e) => {
32494
32560
  var t = comment();
32495
32561
  html(first_child(t), () => o()(get(h))), append(e, t);
32496
- }, lt = (e) => {
32562
+ }, ut = (e) => {
32497
32563
  var t = comment();
32498
32564
  each(first_child(t), 17, () => get(h).split(""), index, (e, t, n) => {
32499
32565
  var i = comment();
@@ -32502,15 +32568,15 @@ function TypewriterText(e, t) {
32502
32568
  index: n
32503
32569
  })), append(e, i);
32504
32570
  }), append(e, t);
32505
- }, ut = (e) => {
32571
+ }, dt = (e) => {
32506
32572
  var t = text();
32507
32573
  template_effect(() => set_text(t, get(h))), append(e, t);
32508
32574
  };
32509
- return if_block(ot, (e) => {
32510
- typeof o() == "function" ? e(ct) : u() ? e(lt, 1) : e(ut, -1);
32511
- }), reset(it), template_effect(() => {
32512
- at = set_class(it, 1, `typewriter-text ${p() ?? "" ?? ""}`, "svelte-12jnsxo", at, { plain: typeof o() != "function" }), set_attribute(it, "data-pw", typeof f() == "string" ? f() : null), set_attribute(it, "testid", typeof f() == "string" ? f() : null);
32513
- }), append(e, it), pop(Ue);
32575
+ return if_block(ct, (e) => {
32576
+ typeof o() == "function" ? e(lt) : u() ? e(ut, 1) : e(dt, -1);
32577
+ }), reset(at), template_effect(() => {
32578
+ ot = set_class(at, 1, `typewriter-text ${p() ?? "" ?? ""}`, "svelte-12jnsxo", ot, { plain: typeof o() != "function" }), set_attribute(at, "data-pw", typeof f() == "string" ? f() : null), set_attribute(at, "testid", typeof f() == "string" ? f() : null);
32579
+ }), append(e, at), pop(it);
32514
32580
  }
32515
32581
  create_custom_element(TypewriterText, {
32516
32582
  text: {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/svelte-ui-components",
3
- "version": "4.10.4",
3
+ "version": "4.11.0",
4
4
  "description": "A themeable Svelte 5 UI component library with CSS custom property driven styling",
5
5
  "keywords": [
6
6
  "svelte",