@streamscloud/kit 0.10.7-1781512309325 → 0.10.7-1781528212938

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.
@@ -104,9 +104,11 @@
104
104
  --sc-kit--field--padding-inline--md: 0.625rem; // 10px
105
105
  --sc-kit--field--padding-inline--lg: 0.75rem; // 12px
106
106
 
107
+ --sc-kit--field--icon--size--xs: 0.8125rem; // 13px
107
108
  --sc-kit--field--icon--size--sm: 0.875rem; // 14px
108
109
  --sc-kit--field--icon--size--md: 1rem; // 16px
109
110
  --sc-kit--field--icon--size--lg: 1.125rem; // 18px
111
+ --sc-kit--field--icon--size--xl: 1.25rem; // 20px
110
112
 
111
113
  // ============================================================
112
114
  // RADII
@@ -1,8 +1,9 @@
1
1
  <script lang="ts">import { Spinner } from '../_internal/spinner';
2
- import { IconSlot } from '../icon';
3
- const { variant = 'primary', size = 'md', disabled = false, loading = false, fullWidth = false, 'aria-label': ariaLabel, icon, iconPosition = 'leading', children, ...mode } = $props();
2
+ import { CONTROL_ICON_SIZE, IconSlot } from '../icon';
3
+ const { variant = 'primary', size = 'md', iconScale = 'default', disabled = false, loading = false, fullWidth = false, 'aria-label': ariaLabel, icon, iconPosition = 'leading', children, ...mode } = $props();
4
4
  const inactive = $derived(disabled || loading);
5
5
  const isIconOnly = $derived(!children && (!!icon || loading));
6
+ const iconFallbacks = $derived({ size: CONTROL_ICON_SIZE[size], scale: iconScale });
6
7
  const disabledVariantClass = $derived(inactive ? `btn--${variant}-disabled` : '');
7
8
  const anchorRel = $derived.by(() => {
8
9
  if (mode.type !== 'anchor') {
@@ -32,13 +33,13 @@ const handleClick = (e) => {
32
33
  {#if loading}
33
34
  <span class="btn__spinner"><Spinner /></span>
34
35
  {:else if icon && iconPosition === 'leading'}
35
- <span class="btn__icon" aria-hidden="true"><IconSlot icon={icon} /></span>
36
+ <span class="btn__icon" aria-hidden="true"><IconSlot icon={icon} fallbacks={iconFallbacks} /></span>
36
37
  {/if}
37
38
  {#if children}
38
39
  <span class="btn__label">{@render children()}</span>
39
40
  {/if}
40
41
  {#if icon && iconPosition === 'trailing' && children}
41
- <span class="btn__icon" aria-hidden="true"><IconSlot icon={icon} /></span>
42
+ <span class="btn__icon" aria-hidden="true"><IconSlot icon={icon} fallbacks={iconFallbacks} /></span>
42
43
  {/if}
43
44
  {/snippet}
44
45
 
@@ -103,7 +104,6 @@ Pass `type="anchor"` to render as `<a>` with `href`. Otherwise `type` is the nat
103
104
  | `--sc-kit--button--padding-inline` | Inline (horizontal) padding | per size |
104
105
  | `--sc-kit--button--font-size` | Label font size | per size |
105
106
  | `--sc-kit--button--gap` | Gap between icon and label | per size |
106
- | `--sc-kit--button--icon-size` | Icon / spinner size | per size (14 / 14 / 16 / 20 px for xs/sm/md/lg) |
107
107
  | `--sc-kit--button--border-radius` | Corner rounding | `var(--sc-kit--radius--md)` |
108
108
  | `--sc-kit--button--font-weight` | Font weight | `var(--sc-kit--font-weight--regular)` |
109
109
  | `--sc-kit--button--width` | Explicit width | `fit-content` |
@@ -123,7 +123,7 @@ Pass `type="anchor"` to render as `<a>` with `href`. Otherwise `type` is the nat
123
123
  --_btn--padding-inline: var(--sc-kit--button--padding-inline, var(--_btn--size-padding-inline));
124
124
  --_btn--font-size: var(--sc-kit--button--font-size, var(--_btn--size-font-size));
125
125
  --_btn--gap: var(--sc-kit--button--gap, var(--_btn--size-gap));
126
- --_btn--icon-size: var(--sc-kit--button--icon-size, var(--_btn--size-icon-size));
126
+ --_btn--icon-size: var(--_btn--size-icon-size);
127
127
  --_btn--width: var(--sc-kit--button--width, fit-content);
128
128
  --_btn--min-width: var(--sc-kit--button--min-width, 0);
129
129
  --_btn--max-width: var(--sc-kit--button--max-width, 100%);
@@ -175,13 +175,10 @@ Pass `type="anchor"` to render as `<a>` with `href`. Otherwise `type` is the nat
175
175
  text-overflow: ellipsis;
176
176
  }
177
177
  .btn__icon {
178
- --sc-kit--icon--size: var(--_btn--icon-size);
179
178
  flex-shrink: 0;
180
179
  display: inline-flex;
181
180
  align-items: center;
182
181
  justify-content: center;
183
- width: var(--_btn--icon-size);
184
- height: var(--_btn--icon-size);
185
182
  }
186
183
  .btn__spinner {
187
184
  --sc-kit--spinner--size: var(--_btn--icon-size);
@@ -202,28 +199,28 @@ Pass `type="anchor"` to render as `<a>` with `href`. Otherwise `type` is the nat
202
199
  --_btn--size-padding-inline: var(--sc-kit--space--2);
203
200
  --_btn--size-font-size: var(--sc-kit--font-size--xs);
204
201
  --_btn--size-gap: var(--sc-kit--space--1);
205
- --_btn--size-icon-size: 0.875rem;
202
+ --_btn--size-icon-size: var(--sc-kit--field--icon--size--xs);
206
203
  }
207
204
  .btn--sm {
208
205
  --_btn--size-height: 1.75rem;
209
206
  --_btn--size-padding-inline: var(--sc-kit--space--3);
210
207
  --_btn--size-font-size: var(--sc-kit--font-size--sm);
211
208
  --_btn--size-gap: var(--sc-kit--space--1);
212
- --_btn--size-icon-size: 0.875rem;
209
+ --_btn--size-icon-size: var(--sc-kit--field--icon--size--sm);
213
210
  }
214
211
  .btn--md {
215
212
  --_btn--size-height: 2rem;
216
213
  --_btn--size-padding-inline: var(--sc-kit--space--4);
217
214
  --_btn--size-font-size: var(--sc-kit--font-size--md);
218
215
  --_btn--size-gap: var(--sc-kit--space--2);
219
- --_btn--size-icon-size: 1rem;
216
+ --_btn--size-icon-size: var(--sc-kit--field--icon--size--md);
220
217
  }
221
218
  .btn--lg {
222
219
  --_btn--size-height: 2.5rem;
223
220
  --_btn--size-padding-inline: var(--sc-kit--space--6);
224
221
  --_btn--size-font-size: var(--sc-kit--font-size--lg);
225
222
  --_btn--size-gap: var(--sc-kit--space--2);
226
- --_btn--size-icon-size: 1.25rem;
223
+ --_btn--size-icon-size: var(--sc-kit--field--icon--size--lg);
227
224
  }
228
225
  .btn--icon-only {
229
226
  --sc-kit--button--padding-inline: 0;
@@ -6,6 +6,8 @@ type BaseProps = {
6
6
  variant?: ButtonVariant;
7
7
  /** @default 'md' */
8
8
  size?: ButtonSize;
9
+ /** Bump the icon one step up the scale relative to `size`, leaving height/text unchanged. @default 'default' */
10
+ iconScale?: 'default' | 'large';
9
11
  disabled?: boolean;
10
12
  /** Renders a spinner in place of the icon (when leading) and blocks clicks. */
11
13
  loading?: boolean;
@@ -61,7 +63,6 @@ type Props = ButtonModeProps | AnchorModeProps;
61
63
  * | `--sc-kit--button--padding-inline` | Inline (horizontal) padding | per size |
62
64
  * | `--sc-kit--button--font-size` | Label font size | per size |
63
65
  * | `--sc-kit--button--gap` | Gap between icon and label | per size |
64
- * | `--sc-kit--button--icon-size` | Icon / spinner size | per size (14 / 14 / 16 / 20 px for xs/sm/md/lg) |
65
66
  * | `--sc-kit--button--border-radius` | Corner rounding | `var(--sc-kit--radius--md)` |
66
67
  * | `--sc-kit--button--font-weight` | Font weight | `var(--sc-kit--font-weight--regular)` |
67
68
  * | `--sc-kit--button--width` | Explicit width | `fit-content` |
@@ -15,7 +15,7 @@ let { action, on } = $props();
15
15
  action.callback?.();
16
16
  on?.click?.();
17
17
  }}>
18
- <IconSlot icon={action.icon} color="text" />
18
+ <IconSlot icon={action.icon} fallbacks={{ color: 'text' }} />
19
19
  </button>
20
20
 
21
21
  <!--
@@ -18,7 +18,7 @@ const featureItemTag = $derived(`h${Math.min(titleLevel + 2, 6)}`);
18
18
  <div class="feature-intro__body">
19
19
  {#if eyebrow}
20
20
  <Badge variant="accent">
21
- {#if eyebrow.icon}<IconSlot icon={eyebrow.icon} size="sm" />{/if}
21
+ {#if eyebrow.icon}<IconSlot icon={eyebrow.icon} fallbacks={{ size: 'sm' }} />{/if}
22
22
  {eyebrow.label}
23
23
  </Badge>
24
24
  {/if}
@@ -53,7 +53,7 @@ const featureItemTag = $derived(`h${Math.min(titleLevel + 2, 6)}`);
53
53
  {#each features as feature, i (i)}
54
54
  <li class="feature-intro__feature">
55
55
  {#if feature.icon}
56
- <div class="feature-intro__feature-icon" aria-hidden="true"><IconSlot icon={feature.icon} size="md" /></div>
56
+ <div class="feature-intro__feature-icon" aria-hidden="true"><IconSlot icon={feature.icon} fallbacks={{ size: 'md' }} /></div>
57
57
  {/if}
58
58
  <div class="feature-intro__feature-body">
59
59
  <svelte:element this={featureItemTag} class="feature-intro__feature-title">
@@ -19,6 +19,7 @@ plan / tier indicators, etc.
19
19
  -->
20
20
 
21
21
  <style>.grid-card-badge-field {
22
- display: contents;
23
22
  --sc-kit--icon--size: 0.875em;
23
+ display: flex;
24
+ align-items: center;
24
25
  }</style>
@@ -4,7 +4,7 @@ export {};
4
4
 
5
5
  <div class="grid-card-field" class:grid-card-field--multiline={multiline} class:grid-card-field--vertical={vertical}>
6
6
  <span class="grid-card-field__label" class:grid-card-field__label--vertical={vertical}>{label}</span>
7
- <div class="grid-card-field__content" class:grid-card-field__content--multiline={multiline} class:grid-card-field__content--vertical={vertical}>
7
+ <div class="grid-card-field__content" class:grid-card-field__content--vertical={vertical}>
8
8
  {@render children()}
9
9
  </div>
10
10
  </div>
@@ -55,15 +55,10 @@ content; set `vertical` to stack the label above the content (escapes the subgri
55
55
  padding: 0;
56
56
  }
57
57
  .grid-card-field__content {
58
- display: flex;
59
- align-items: center;
60
58
  padding-block: var(--_gcf--padding-block);
61
59
  padding-inline-end: var(--_gcf--padding-inline);
62
60
  min-width: 0;
63
61
  }
64
- .grid-card-field__content--multiline {
65
- align-items: flex-start;
66
- }
67
62
  .grid-card-field__content--vertical {
68
63
  padding: 0;
69
64
  }</style>
@@ -1,19 +1,21 @@
1
1
  <script lang="ts">import Icon from './cmp.icon.svelte';
2
- import { splitIcon } from './icon-utils';
3
- const { icon, color, size } = $props();
2
+ import { scaleUp, splitIcon } from './icon-utils';
3
+ const { icon, fallbacks } = $props();
4
4
  const split = $derived(splitIcon(icon));
5
+ const fallbackSize = $derived(fallbacks?.scale === 'large' ? scaleUp(fallbacks?.size) : fallbacks?.size);
5
6
  </script>
6
7
 
7
8
  {#if split.snippet}
8
9
  {@render split.snippet()}
9
10
  {:else if split.src}
10
- <Icon src={split.src} color={split.color ?? color ?? null} size={split.size ?? size ?? null} />
11
+ <Icon src={split.src} color={split.color ?? fallbacks?.color ?? null} size={split.size ?? fallbackSize ?? null} />
11
12
  {/if}
12
13
 
13
14
  <!--
14
15
  @component
15
16
  Renders an `IconProp` — discriminates between snippet, string SVG, and `{ src, color?, size? }` object.
16
17
  Use this wherever a component model carries an `icon: IconProp` field, so the discrimination logic
17
- lives in one place. `color` and `size` props provide fallbacks when the icon itself doesn't specify
18
- them; they are ignored when the icon is a snippet (snippets render themselves).
18
+ lives in one place. `fallbacks.size` / `fallbacks.color` apply only when the icon object omits its own
19
+ (ignored for snippets); `fallbacks.scale='large'` bumps the fallback size one step. An explicit
20
+ `icon.size` / `icon.color` always wins.
19
21
  -->
@@ -2,16 +2,23 @@ import type { IconColor, IconProp, IconSize } from './types';
2
2
  type Props = {
3
3
  /** Icon to render — string SVG source, `{ src, color?, size? }` object, or custom snippet. */
4
4
  icon?: IconProp | null;
5
- /** Fallback color when `icon` doesn't carry one (ignored for snippets). */
6
- color?: IconColor;
7
- /** Fallback size when `icon` doesn't carry one (ignored for snippets). */
8
- size?: IconSize;
5
+ /**
6
+ * Values applied only when the `icon` object omits its own (ignored for snippets). `size` / `color`
7
+ * fill the gaps; `scale: 'large'` bumps the fallback `size` one step up. An explicit `icon.size` /
8
+ * `icon.color` always wins — scale never touches it.
9
+ */
10
+ fallbacks?: {
11
+ size?: IconSize;
12
+ color?: IconColor;
13
+ scale?: 'default' | 'large';
14
+ };
9
15
  };
10
16
  /**
11
17
  * Renders an `IconProp` — discriminates between snippet, string SVG, and `{ src, color?, size? }` object.
12
18
  * Use this wherever a component model carries an `icon: IconProp` field, so the discrimination logic
13
- * lives in one place. `color` and `size` props provide fallbacks when the icon itself doesn't specify
14
- * them; they are ignored when the icon is a snippet (snippets render themselves).
19
+ * lives in one place. `fallbacks.size` / `fallbacks.color` apply only when the icon object omits its own
20
+ * (ignored for snippets); `fallbacks.scale='large'` bumps the fallback size one step. An explicit
21
+ * `icon.size` / `icon.color` always wins.
15
22
  */
16
23
  declare const Cmp: import("svelte").Component<Props, {}, "">;
17
24
  type Cmp = ReturnType<typeof Cmp>;
@@ -20,7 +20,12 @@ onMount(() => {
20
20
  class:icon--sm={size === 'sm'}
21
21
  class:icon--md={size === 'md'}
22
22
  class:icon--lg={size === 'lg'}
23
- class:icon--xlg={size === 'xlg'}>
23
+ class:icon--xlg={size === 'xlg'}
24
+ class:icon--control-xs={size === 'control-xs'}
25
+ class:icon--control-sm={size === 'control-sm'}
26
+ class:icon--control-md={size === 'control-md'}
27
+ class:icon--control-lg={size === 'control-lg'}
28
+ class:icon--control-xl={size === 'control-xl'}>
24
29
  {#if mounted}
25
30
  {@html HtmlHelper.sanitizeSvg(src)}
26
31
  {/if}
@@ -55,6 +60,11 @@ Renders an inline SVG icon with configurable size, color presets, and optional s
55
60
  | `icon--md` | `1.25rem` (20px) |
56
61
  | `icon--lg` | `2rem` (32px) |
57
62
  | `icon--xlg` | `3rem` (48px) |
63
+ | `icon--control-xs` | `var(--sc-kit--field--icon--size--xs)` (13px) |
64
+ | `icon--control-sm` | `var(--sc-kit--field--icon--size--sm)` (14px) |
65
+ | `icon--control-md` | `var(--sc-kit--field--icon--size--md)` (16px) |
66
+ | `icon--control-lg` | `var(--sc-kit--field--icon--size--lg)` (18px) |
67
+ | `icon--control-xl` | `var(--sc-kit--field--icon--size--xl)` (20px) |
58
68
  -->
59
69
 
60
70
  <style>.icon {
@@ -104,6 +114,21 @@ Renders an inline SVG icon with configurable size, color presets, and optional s
104
114
  .icon--xlg {
105
115
  --sc-kit--icon--size: 3rem;
106
116
  }
117
+ .icon--control-xs {
118
+ --sc-kit--icon--size: var(--sc-kit--field--icon--size--xs);
119
+ }
120
+ .icon--control-sm {
121
+ --sc-kit--icon--size: var(--sc-kit--field--icon--size--sm);
122
+ }
123
+ .icon--control-md {
124
+ --sc-kit--icon--size: var(--sc-kit--field--icon--size--md);
125
+ }
126
+ .icon--control-lg {
127
+ --sc-kit--icon--size: var(--sc-kit--field--icon--size--lg);
128
+ }
129
+ .icon--control-xl {
130
+ --sc-kit--icon--size: var(--sc-kit--field--icon--size--xl);
131
+ }
107
132
  .icon :global(svg) {
108
133
  display: inline-block;
109
134
  color: inherit;
@@ -4,7 +4,11 @@ interface Props {
4
4
  src: string;
5
5
  /** Predefined color preset applied to the icon */
6
6
  color?: IconColor | null;
7
- /** Size preset. Sets `--sc-kit--icon--size` to 14 / 20 / 32 / 48 px respectively. Omit to fall through to the CSS cascade (default 1.25rem = 20px). */
7
+ /**
8
+ * Size preset. Standalone visual weight `sm | md | lg | xlg` = 14 / 20 / 32 / 48 px;
9
+ * control-paired `control-xs | control-sm | control-md | control-lg | control-xl` = 13 / 14 / 16 / 18 / 20 px.
10
+ * Omit to fall through to the CSS cascade (default 1.25rem = 20px).
11
+ */
8
12
  size?: IconSize | null;
9
13
  }
10
14
  /**
@@ -32,6 +36,11 @@ interface Props {
32
36
  * | `icon--md` | `1.25rem` (20px) |
33
37
  * | `icon--lg` | `2rem` (32px) |
34
38
  * | `icon--xlg` | `3rem` (48px) |
39
+ * | `icon--control-xs` | `var(--sc-kit--field--icon--size--xs)` (13px) |
40
+ * | `icon--control-sm` | `var(--sc-kit--field--icon--size--sm)` (14px) |
41
+ * | `icon--control-md` | `var(--sc-kit--field--icon--size--md)` (16px) |
42
+ * | `icon--control-lg` | `var(--sc-kit--field--icon--size--lg)` (18px) |
43
+ * | `icon--control-xl` | `var(--sc-kit--field--icon--size--xl)` (20px) |
35
44
  */
36
45
  declare const Cmp: import("svelte").Component<Props, {}, "">;
37
46
  type Cmp = ReturnType<typeof Cmp>;
@@ -1,9 +1,19 @@
1
1
  import type { IconColor, IconProp, IconSize } from './types';
2
2
  import type { Snippet } from 'svelte';
3
+ /** Maps a control's size key to its control-scale `IconSize`. Validated against `IconControlSize` so a prefix/scale rename fails to compile here. */
4
+ export declare const CONTROL_ICON_SIZE: {
5
+ xs: "control-xs";
6
+ sm: "control-sm";
7
+ md: "control-md";
8
+ lg: "control-lg";
9
+ xl: "control-xl";
10
+ };
3
11
  export type SplitIcon = {
4
12
  snippet: Snippet | null;
5
13
  src: string | null;
6
14
  color: IconColor | null;
7
15
  size: IconSize | null;
8
16
  };
17
+ /** One step up the icon-size scale (caps at the largest). Backs IconSlot's `scale: 'large'` fallback. */
18
+ export declare const scaleUp: (size: IconSize | null | undefined) => IconSize | undefined;
9
19
  export declare const splitIcon: (icon: IconProp | undefined | null) => SplitIcon;
@@ -1,3 +1,24 @@
1
+ /** Maps a control's size key to its control-scale `IconSize`. Validated against `IconControlSize` so a prefix/scale rename fails to compile here. */
2
+ export const CONTROL_ICON_SIZE = {
3
+ xs: 'control-xs',
4
+ sm: 'control-sm',
5
+ md: 'control-md',
6
+ lg: 'control-lg',
7
+ xl: 'control-xl'
8
+ };
9
+ const SIZE_STEP_UP = {
10
+ sm: 'md',
11
+ md: 'lg',
12
+ lg: 'xlg',
13
+ xlg: 'xlg',
14
+ 'control-xs': 'control-sm',
15
+ 'control-sm': 'control-md',
16
+ 'control-md': 'control-lg',
17
+ 'control-lg': 'control-xl',
18
+ 'control-xl': 'control-xl'
19
+ };
20
+ /** One step up the icon-size scale (caps at the largest). Backs IconSlot's `scale: 'large'` fallback. */
21
+ export const scaleUp = (size) => (!size ? undefined : SIZE_STEP_UP[size]);
1
22
  export const splitIcon = (icon) => {
2
23
  if (icon === null || icon === undefined) {
3
24
  return { snippet: null, src: null, color: null, size: null };
@@ -1,4 +1,4 @@
1
1
  export { default as Icon } from './cmp.icon.svelte';
2
2
  export { default as IconSlot } from './cmp.icon-slot.svelte';
3
- export { splitIcon } from './icon-utils';
4
- export type { IconColor, IconProp, IconSize } from './types';
3
+ export { CONTROL_ICON_SIZE, scaleUp, splitIcon } from './icon-utils';
4
+ export type { IconColor, IconControlSize, IconControlSizeKey, IconProp, IconSize } from './types';
@@ -1,3 +1,3 @@
1
1
  export { default as Icon } from './cmp.icon.svelte';
2
2
  export { default as IconSlot } from './cmp.icon-slot.svelte';
3
- export { splitIcon } from './icon-utils';
3
+ export { CONTROL_ICON_SIZE, scaleUp, splitIcon } from './icon-utils';
@@ -1,6 +1,9 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  export type IconColor = 'accent' | 'muted' | 'success' | 'warning' | 'danger' | 'text' | 'on-accent';
3
- export type IconSize = 'sm' | 'md' | 'lg' | 'xlg';
3
+ export type IconStandaloneSize = 'sm' | 'md' | 'lg' | 'xlg';
4
+ export type IconControlSizeKey = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
5
+ export type IconControlSize = 'control-xs' | 'control-sm' | 'control-md' | 'control-lg' | 'control-xl';
6
+ export type IconSize = IconStandaloneSize | IconControlSize;
4
7
  export type IconProp = string | {
5
8
  src: string;
6
9
  color?: IconColor;
@@ -1,5 +1,6 @@
1
- <script lang="ts">import { IconSlot } from '../icon';
2
- let { icon, iconPosition = 'leading', secondaryIcon, trimText = false, hideText = false, size, children } = $props();
1
+ <script lang="ts">import { CONTROL_ICON_SIZE, IconSlot } from '../icon';
2
+ let { icon, iconPosition = 'leading', secondaryIcon, trimText = false, hideText = false, size, iconScale = 'default', children } = $props();
3
+ const iconFallbacks = $derived(size ? { size: CONTROL_ICON_SIZE[size], scale: iconScale } : { scale: iconScale });
3
4
  </script>
4
5
 
5
6
  <span
@@ -9,7 +10,7 @@ let { icon, iconPosition = 'leading', secondaryIcon, trimText = false, hideText
9
10
  class:icon-text--md={size === 'md'}
10
11
  class:icon-text--lg={size === 'lg'}>
11
12
  <span class="icon-text__icon">
12
- <IconSlot icon={icon} />
13
+ <IconSlot icon={icon} fallbacks={iconFallbacks} />
13
14
  </span>
14
15
  {#if children && !hideText}
15
16
  <span class="icon-text__text" class:icon-text__text--trim={trimText}>
@@ -18,7 +19,7 @@ let { icon, iconPosition = 'leading', secondaryIcon, trimText = false, hideText
18
19
  {/if}
19
20
  {#if secondaryIcon}
20
21
  <span class="icon-text__secondary">
21
- <IconSlot icon={secondaryIcon} />
22
+ <IconSlot icon={secondaryIcon} fallbacks={iconFallbacks} />
22
23
  </span>
23
24
  {/if}
24
25
  </span>
@@ -70,15 +71,12 @@ status" dropdown-trigger patterns. Each icon prop accepts a string SVG source, a
70
71
  }
71
72
  .icon-text--sm {
72
73
  --sc-kit--icon-text--text--font-size: var(--sc-kit--font-size--sm);
73
- --sc-kit--icon-text--icon--font-size: 0.875rem;
74
74
  }
75
75
  .icon-text--md {
76
76
  --sc-kit--icon-text--text--font-size: var(--sc-kit--font-size--md);
77
- --sc-kit--icon-text--icon--font-size: 1rem;
78
77
  }
79
78
  .icon-text--lg {
80
79
  --sc-kit--icon-text--text--font-size: var(--sc-kit--font-size--lg);
81
- --sc-kit--icon-text--icon--font-size: 1.25rem;
82
80
  }
83
81
  .icon-text__text {
84
82
  font-size: var(--_icon-text--text--font-size);
@@ -11,8 +11,10 @@ type Props = {
11
11
  trimText?: boolean;
12
12
  /** Hide text, showing only the icon(s) */
13
13
  hideText?: boolean;
14
- /** Size preset matching `Button` of the same size — text/icon px: sm 12/14, md 14/16, lg 16/20. Unset: text + icon follow the inherited font size (`1em`). */
14
+ /** Size preset matching `Button` of the same size — text/icon px: sm 12/14, md 14/16, lg 16/18. Unset: text + icon follow the inherited font size (`1em`). */
15
15
  size?: 'sm' | 'md' | 'lg';
16
+ /** Bump the icon(s) one step up the scale relative to `size`, text unchanged (sm 14→16, md 16→18, lg 18→20). @default 'default' */
17
+ iconScale?: 'default' | 'large';
16
18
  children?: Snippet;
17
19
  };
18
20
  /**
@@ -10,7 +10,7 @@ const { title, triggerLabel, icon, size = 'sm', position = 'bottom-end', childre
10
10
  <Popover position={position} keepOpen>
11
11
  {#snippet trigger()}
12
12
  <Button type="button" variant="secondary" size={size}>
13
- <IconText icon={icon} secondaryIcon={IconChevronDown}>{triggerLabel}</IconText>
13
+ <IconText icon={icon} secondaryIcon={IconChevronDown} size={size} iconScale="large">{triggerLabel}</IconText>
14
14
  </Button>
15
15
  {/snippet}
16
16
  <ToolbarPanel title={title} footer={footer}>
@@ -1,9 +1,11 @@
1
1
  <script lang="ts">import { Utils } from '../../core/utils';
2
+ import { CONTROL_ICON_SIZE, scaleUp } from '../icon';
2
3
  import { Input } from '../input';
3
4
  import IconSearch from '@fluentui/svg-icons/icons/search_20_regular.svg?raw';
4
- const { value, collapsedIconColor, placeholder = '', size = 'sm', debounce = 0, on } = $props();
5
+ const { value, collapsedIconColor, collapsedIconSize, placeholder = '', size = 'sm', debounce = 0, on } = $props();
5
6
  let focused = $state(false);
6
7
  const expanded = $derived(focused || !!value);
8
+ const collapsedSize = $derived(collapsedIconSize ?? scaleUp(CONTROL_ICON_SIZE[size]));
7
9
  const onInput = (v) => {
8
10
  on?.input?.(v);
9
11
  };
@@ -15,7 +17,7 @@ const onInputDebounced = $derived(debounce > 0 ? Utils.debounce(onInput, debounc
15
17
  value={value}
16
18
  size={size}
17
19
  placeholder={placeholder}
18
- icon={{ src: IconSearch, color: expanded ? undefined : (collapsedIconColor ?? 'accent') }}
20
+ icon={{ src: IconSearch, color: expanded ? undefined : (collapsedIconColor ?? 'accent'), size: expanded ? undefined : collapsedSize }}
19
21
  clearable
20
22
  borderless={!expanded}
21
23
  on={{ input: onInputDebounced, change: onInputDebounced, focus: () => (focused = true), blur: () => (focused = false) }} />
@@ -1,7 +1,9 @@
1
- import type { IconColor } from '../icon';
1
+ import { type IconColor, type IconSize } from '../icon';
2
2
  type Props = {
3
3
  value: string;
4
4
  collapsedIconColor?: IconColor;
5
+ /** Icon size while collapsed (icon-only). Defaults to one step larger than the inline icon for legibility. */
6
+ collapsedIconSize?: IconSize;
5
7
  placeholder?: string;
6
8
  /** Size preset (shared with Input / DatePicker / Select). @default 'sm' */
7
9
  size?: 'sm' | 'md' | 'lg';
@@ -1,9 +1,10 @@
1
- <script lang="ts">import { Icon } from '../icon';
1
+ <script lang="ts">import { CONTROL_ICON_SIZE, Icon } from '../icon';
2
2
  import { ToolbarValueStepperLocalization } from './toolbar-value-stepper-localization';
3
3
  import IconChevronLeft from '@fluentui/svg-icons/icons/chevron_left_16_regular.svg?raw';
4
4
  import IconChevronRight from '@fluentui/svg-icons/icons/chevron_right_16_regular.svg?raw';
5
5
  const { value, min = 0, max = 100, step = 1, valueSuffix = '', size = 'sm', on } = $props();
6
6
  const localization = new ToolbarValueStepperLocalization();
7
+ const iconSize = $derived(CONTROL_ICON_SIZE[size]);
7
8
  const atMin = $derived(value <= min);
8
9
  const atMax = $derived(value >= max);
9
10
  const decrease = () => {
@@ -16,11 +17,11 @@ const increase = () => {
16
17
 
17
18
  <div class="toolbar-value-stepper toolbar-value-stepper--{size}" role="group" aria-label={localization.value}>
18
19
  <button type="button" class="toolbar-value-stepper__btn" onclick={decrease} disabled={atMin} aria-label={localization.decreaseValue}>
19
- <Icon src={IconChevronLeft} />
20
+ <Icon src={IconChevronLeft} size={iconSize} />
20
21
  </button>
21
22
  <span class="toolbar-value-stepper__value">{value}{valueSuffix}</span>
22
23
  <button type="button" class="toolbar-value-stepper__btn" onclick={increase} disabled={atMax} aria-label={localization.increaseValue}>
23
- <Icon src={IconChevronRight} />
24
+ <Icon src={IconChevronRight} size={iconSize} />
24
25
  </button>
25
26
  </div>
26
27
 
@@ -78,7 +78,7 @@ const handleChange = (updatedItems) => {
78
78
  <Popover position="bottom-start" keepOpen>
79
79
  {#snippet trigger()}
80
80
  <Button type="button" variant="secondary" size="sm">
81
- <IconText icon={{ src: IconColumnTwo, color: 'accent' }} secondaryIcon={IconChevronDown}>{localization.columns}</IconText>
81
+ <IconText icon={{ src: IconColumnTwo, color: 'accent' }} secondaryIcon={IconChevronDown} size="sm" iconScale="large">{localization.columns}</IconText>
82
82
  </Button>
83
83
  {/snippet}
84
84
  <div class="columns-manager">
@@ -39,7 +39,7 @@ const handleCloseKeydown = (event) => {
39
39
  <span class="tab__label">{tab.label}</span>
40
40
  {#if closable}
41
41
  <span class="tab__close" role="button" tabindex="0" aria-label={localization.close} onclick={handleClose} onkeydown={handleCloseKeydown}>
42
- <IconSlot icon={IconDismiss} size="sm" />
42
+ <IconSlot icon={IconDismiss} fallbacks={{ size: 'sm' }} />
43
43
  </span>
44
44
  {/if}
45
45
  </button>
@@ -8,7 +8,7 @@ const ratio = $derived(max === 0 ? 0 : value / max);
8
8
  <div class="usage-row__label">
9
9
  <span class="usage-row__title">
10
10
  {#if icon}
11
- <span class="usage-row__icon"><IconSlot icon={icon} size="sm" /></span>
11
+ <span class="usage-row__icon"><IconSlot icon={icon} fallbacks={{ size: 'sm' }} /></span>
12
12
  {/if}
13
13
  {title}
14
14
  </span>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamscloud/kit",
3
- "version": "0.10.7-1781512309325",
3
+ "version": "0.10.7-1781528212938",
4
4
  "author": "StreamsCloud",
5
5
  "repository": {
6
6
  "type": "git",