@snack-uikit/segmented-control 0.5.0 → 0.6.1-preview-2df7e7b5.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 0.6.0 (2025-05-28)
7
+
8
+
9
+ ### Features
10
+
11
+ * **PDS-1990:** added xs size for segmented control ([0f8fb0d](https://github.com/cloud-ru-tech/snack-uikit/commit/0f8fb0de09568eb983c685118068870a03ad3f92))
12
+
13
+
14
+
15
+
16
+
6
17
  # 0.5.0 (2025-05-21)
7
18
 
8
19
 
package/README.md CHANGED
@@ -19,7 +19,7 @@ SegmentedControl
19
19
  | defaultValue | `IdType` | - | ID выбранного по умолчанию сегмента. (в uncontrolled режиме) |
20
20
  | onChange | `(value: Value) => void` | - | Колбек смены выбранного сегмента. |
21
21
  | className | `string` | - | CSS-класс контейнера. |
22
- | size | enum Size: `"s"`, `"m"`, `"l"` | m | Размер компонента. |
22
+ | size | enum Size: `"xs"`, `"s"`, `"m"`, `"l"` | m | Размер компонента. |
23
23
  | outline | `boolean` | - | Обводка |
24
24
  | width | enum Width: `"auto"`, `"full"` | auto | Управление шириной компонента. |
25
25
  | name | `string` | - | Имя поля |
@@ -28,6 +28,10 @@
28
28
  .container[data-width=full]{
29
29
  display:flex;
30
30
  }
31
+ .container[data-size=xs]::before{
32
+ border-width:var(--border-width-segmented-control-single, 1px);
33
+ border-radius:var(--radius-segmented-control-container-xs, 8px);
34
+ }
31
35
  .container[data-size=s]::before{
32
36
  border-width:var(--border-width-segmented-control-single, 1px);
33
37
  border-radius:var(--radius-segmented-control-container-s, 12px);
@@ -59,6 +63,13 @@
59
63
  background-color:var(--sys-neutral-background2-level, #ffffff);
60
64
  transition:left 0.15s ease-in-out, width 0.15s ease-in-out;
61
65
  }
66
+ .selection[data-size=xs]{
67
+ border-radius:var(--radius-segmented-control-segment-s, 10px);
68
+ padding-left:var(--space-segmented-control-segment-s-icon-only, 2px);
69
+ padding-right:var(--space-segmented-control-segment-s-icon-only, 2px);
70
+ gap:var(--space-segmented-control-segment-s-gap, 4px);
71
+ height:var(--size-segmented-control-segment-s, 28px);
72
+ }
62
73
  .selection[data-size=s]{
63
74
  border-radius:var(--radius-segmented-control-segment-s, 10px);
64
75
  padding-left:var(--space-segmented-control-segment-s-icon-only, 2px);
@@ -1,4 +1,5 @@
1
1
  export declare const SIZE: {
2
+ readonly XS: "xs";
2
3
  readonly S: "s";
3
4
  readonly M: "m";
4
5
  readonly L: "l";
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.WIDTH = exports.SIZE = void 0;
7
7
  exports.SIZE = {
8
+ XS: 'xs',
8
9
  S: 's',
9
10
  M: 'm',
10
11
  L: 'l'
@@ -45,7 +45,7 @@ function Segment(_ref) {
45
45
  "data-test-id": `section-${value}`,
46
46
  "data-active": selected || undefined,
47
47
  "data-disabled": disabled || undefined,
48
- "data-layout": (0, utils_1.getLayout)(icon, label),
48
+ "data-layout": (0, utils_1.getLayout)(icon, label, size),
49
49
  className: (0, classnames_1.default)(styles_module_scss_1.default.segment),
50
50
  onClick: onClick,
51
51
  "data-size": size,
@@ -54,7 +54,7 @@ function Segment(_ref) {
54
54
  "aria-checked": selected,
55
55
  role: 'radio',
56
56
  type: 'button',
57
- children: [icon && (0, jsx_runtime_1.jsx)("div", {
57
+ children: [size !== 'xs' && icon && (0, jsx_runtime_1.jsx)("div", {
58
58
  className: styles_module_scss_1.default.icon,
59
59
  children: icon
60
60
  }), label && (0, jsx_runtime_1.jsx)(truncate_string_1.TruncateString, {
@@ -29,6 +29,27 @@
29
29
  outline-offset:calc(var(--border-state-focus-s-border-width, 2px) * -1);
30
30
  outline-color:var(--sys-available-complementary, #1c1c24);
31
31
  }
32
+ .segment[data-size=xs][data-layout=label-only]{
33
+ border-radius:var(--radius-segmented-control-segment-xs, 6px);
34
+ padding-left:var(--space-segmented-control-segment-xs-from-label, 8px);
35
+ padding-right:var(--space-segmented-control-segment-xs-from-label, 8px);
36
+ gap:var(--space-segmented-control-segment-xs-gap, 2px);
37
+ height:var(--size-segmented-control-segment-xs, 20px);
38
+ }
39
+ .segment[data-size=xs][data-layout=icon-before]{
40
+ border-radius:var(--radius-segmented-control-segment-s, 10px);
41
+ padding-left:var(--space-segmented-control-segment-s-from-icon, 8px);
42
+ padding-right:var(--space-segmented-control-segment-s-from-label, 16px);
43
+ gap:var(--space-segmented-control-segment-s-gap, 4px);
44
+ height:var(--size-segmented-control-segment-s, 28px);
45
+ }
46
+ .segment[data-size=xs][data-layout=icon-only]{
47
+ border-radius:var(--radius-segmented-control-segment-s, 10px);
48
+ padding-left:var(--space-segmented-control-segment-s-icon-only, 2px);
49
+ padding-right:var(--space-segmented-control-segment-s-icon-only, 2px);
50
+ gap:var(--space-segmented-control-segment-s-gap, 4px);
51
+ height:var(--size-segmented-control-segment-s, 28px);
52
+ }
32
53
  .segment[data-size=s][data-layout=label-only]{
33
54
  border-radius:var(--radius-segmented-control-segment-s, 10px);
34
55
  padding-left:var(--space-segmented-control-segment-s-from-label, 16px);
@@ -99,6 +120,14 @@
99
120
  align-items:center;
100
121
  }
101
122
 
123
+ .label[data-size=xs]{
124
+ font-family:var(--sans-label-m-font-family, SB Sans Interface);
125
+ font-weight:var(--sans-label-m-font-weight, Semibold);
126
+ line-height:var(--sans-label-m-line-height, 16px);
127
+ font-size:var(--sans-label-m-font-size, 12px);
128
+ letter-spacing:var(--sans-label-m-letter-spacing, 0px);
129
+ paragraph-spacing:var(--sans-label-m-paragraph-spacing, 6.6px);
130
+ }
102
131
  .label[data-size=s]{
103
132
  font-family:var(--sans-label-m-font-family, SB Sans Interface);
104
133
  font-weight:var(--sans-label-m-font-weight, Semibold);
@@ -1,2 +1,2 @@
1
1
  import { ReactNode } from 'react';
2
- export declare const getLayout: (icon?: ReactNode, label?: string) => "icon-before" | "label-only" | "icon-only";
2
+ export declare const getLayout: (icon?: ReactNode, label?: string, size?: string) => "label-only" | "icon-before" | "icon-only";
package/dist/cjs/utils.js CHANGED
@@ -4,7 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.getLayout = void 0;
7
- const getLayout = (icon, label) => {
7
+ const getLayout = (icon, label, size) => {
8
+ if (size === 'xs') {
9
+ return 'label-only';
10
+ }
8
11
  if (icon && label) {
9
12
  return 'icon-before';
10
13
  }
@@ -28,6 +28,10 @@
28
28
  .container[data-width=full]{
29
29
  display:flex;
30
30
  }
31
+ .container[data-size=xs]::before{
32
+ border-width:var(--border-width-segmented-control-single, 1px);
33
+ border-radius:var(--radius-segmented-control-container-xs, 8px);
34
+ }
31
35
  .container[data-size=s]::before{
32
36
  border-width:var(--border-width-segmented-control-single, 1px);
33
37
  border-radius:var(--radius-segmented-control-container-s, 12px);
@@ -59,6 +63,13 @@
59
63
  background-color:var(--sys-neutral-background2-level, #ffffff);
60
64
  transition:left 0.15s ease-in-out, width 0.15s ease-in-out;
61
65
  }
66
+ .selection[data-size=xs]{
67
+ border-radius:var(--radius-segmented-control-segment-s, 10px);
68
+ padding-left:var(--space-segmented-control-segment-s-icon-only, 2px);
69
+ padding-right:var(--space-segmented-control-segment-s-icon-only, 2px);
70
+ gap:var(--space-segmented-control-segment-s-gap, 4px);
71
+ height:var(--size-segmented-control-segment-s, 28px);
72
+ }
62
73
  .selection[data-size=s]{
63
74
  border-radius:var(--radius-segmented-control-segment-s, 10px);
64
75
  padding-left:var(--space-segmented-control-segment-s-icon-only, 2px);
@@ -1,4 +1,5 @@
1
1
  export declare const SIZE: {
2
+ readonly XS: "xs";
2
3
  readonly S: "s";
3
4
  readonly M: "m";
4
5
  readonly L: "l";
@@ -1,4 +1,5 @@
1
1
  export const SIZE = {
2
+ XS: 'xs',
2
3
  S: 's',
3
4
  M: 'm',
4
5
  L: 'l',
@@ -16,6 +16,6 @@ export function Segment({ size, label, value, selected, onClick, disabled, icon,
16
16
  onSelectionUpdated(buttonRef.current);
17
17
  }
18
18
  }, [selected, buttonRef, onSelectionUpdated]);
19
- const segment = (_jsxs("button", { ref: buttonRef, "data-test-id": `section-${value}`, "data-active": selected || undefined, "data-disabled": disabled || undefined, "data-layout": getLayout(icon, label), className: cn(styles.segment), onClick: onClick, "data-size": size, disabled: disabled, tabIndex: focusable ? 0 : -1, "aria-checked": selected, role: 'radio', type: 'button', children: [icon && _jsx("div", { className: styles.icon, children: icon }), label && _jsx(TruncateString, { className: styles.label, "data-size": size, text: label })] }));
19
+ const segment = (_jsxs("button", { ref: buttonRef, "data-test-id": `section-${value}`, "data-active": selected || undefined, "data-disabled": disabled || undefined, "data-layout": getLayout(icon, label, size), className: cn(styles.segment), onClick: onClick, "data-size": size, disabled: disabled, tabIndex: focusable ? 0 : -1, "aria-checked": selected, role: 'radio', type: 'button', children: [size !== 'xs' && icon && _jsx("div", { className: styles.icon, children: icon }), label && _jsx(TruncateString, { className: styles.label, "data-size": size, text: label })] }));
20
20
  return renderWrapSegment ? renderWrapSegment(segment) : segment;
21
21
  }
@@ -29,6 +29,27 @@
29
29
  outline-offset:calc(var(--border-state-focus-s-border-width, 2px) * -1);
30
30
  outline-color:var(--sys-available-complementary, #1c1c24);
31
31
  }
32
+ .segment[data-size=xs][data-layout=label-only]{
33
+ border-radius:var(--radius-segmented-control-segment-xs, 6px);
34
+ padding-left:var(--space-segmented-control-segment-xs-from-label, 8px);
35
+ padding-right:var(--space-segmented-control-segment-xs-from-label, 8px);
36
+ gap:var(--space-segmented-control-segment-xs-gap, 2px);
37
+ height:var(--size-segmented-control-segment-xs, 20px);
38
+ }
39
+ .segment[data-size=xs][data-layout=icon-before]{
40
+ border-radius:var(--radius-segmented-control-segment-s, 10px);
41
+ padding-left:var(--space-segmented-control-segment-s-from-icon, 8px);
42
+ padding-right:var(--space-segmented-control-segment-s-from-label, 16px);
43
+ gap:var(--space-segmented-control-segment-s-gap, 4px);
44
+ height:var(--size-segmented-control-segment-s, 28px);
45
+ }
46
+ .segment[data-size=xs][data-layout=icon-only]{
47
+ border-radius:var(--radius-segmented-control-segment-s, 10px);
48
+ padding-left:var(--space-segmented-control-segment-s-icon-only, 2px);
49
+ padding-right:var(--space-segmented-control-segment-s-icon-only, 2px);
50
+ gap:var(--space-segmented-control-segment-s-gap, 4px);
51
+ height:var(--size-segmented-control-segment-s, 28px);
52
+ }
32
53
  .segment[data-size=s][data-layout=label-only]{
33
54
  border-radius:var(--radius-segmented-control-segment-s, 10px);
34
55
  padding-left:var(--space-segmented-control-segment-s-from-label, 16px);
@@ -99,6 +120,14 @@
99
120
  align-items:center;
100
121
  }
101
122
 
123
+ .label[data-size=xs]{
124
+ font-family:var(--sans-label-m-font-family, SB Sans Interface);
125
+ font-weight:var(--sans-label-m-font-weight, Semibold);
126
+ line-height:var(--sans-label-m-line-height, 16px);
127
+ font-size:var(--sans-label-m-font-size, 12px);
128
+ letter-spacing:var(--sans-label-m-letter-spacing, 0px);
129
+ paragraph-spacing:var(--sans-label-m-paragraph-spacing, 6.6px);
130
+ }
102
131
  .label[data-size=s]{
103
132
  font-family:var(--sans-label-m-font-family, SB Sans Interface);
104
133
  font-weight:var(--sans-label-m-font-weight, Semibold);
@@ -1,2 +1,2 @@
1
1
  import { ReactNode } from 'react';
2
- export declare const getLayout: (icon?: ReactNode, label?: string) => "icon-before" | "label-only" | "icon-only";
2
+ export declare const getLayout: (icon?: ReactNode, label?: string, size?: string) => "label-only" | "icon-before" | "icon-only";
package/dist/esm/utils.js CHANGED
@@ -1,4 +1,7 @@
1
- export const getLayout = (icon, label) => {
1
+ export const getLayout = (icon, label, size) => {
2
+ if (size === 'xs') {
3
+ return 'label-only';
4
+ }
2
5
  if (icon && label) {
3
6
  return 'icon-before';
4
7
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public"
5
5
  },
6
6
  "title": "Segmented Control",
7
- "version": "0.5.0",
7
+ "version": "0.6.1-preview-2df7e7b5.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -36,10 +36,10 @@
36
36
  "license": "Apache-2.0",
37
37
  "scripts": {},
38
38
  "dependencies": {
39
- "@snack-uikit/truncate-string": "0.6.19",
39
+ "@snack-uikit/truncate-string": "0.6.20-preview-2df7e7b5.0",
40
40
  "@snack-uikit/utils": "3.8.2",
41
41
  "classnames": "2.5.1",
42
42
  "uncontrollable": "8.0.4"
43
43
  },
44
- "gitHead": "0c8846201ac8f73ec80be3e47418fe073619541a"
44
+ "gitHead": "68982219776af04aaffba2391e0dfdba8935f1b0"
45
45
  }
@@ -1,6 +1,6 @@
1
1
  @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-segmentedControl';
2
2
 
3
- $sizes: 's', 'm', 'l';
3
+ $sizes: 'xs', 's', 'm', 'l';
4
4
 
5
5
  .container {
6
6
  @include styles-tokens-segmentedControl.composite-var(styles-tokens-segmentedControl.$segmented-control-container);
@@ -40,7 +40,11 @@ $sizes: 's', 'm', 'l';
40
40
 
41
41
  @each $size in $sizes {
42
42
  &[data-size='#{$size}']::before {
43
- @include styles-tokens-segmentedControl.composite-var(styles-tokens-segmentedControl.$segmented-control, 'background', $size);
43
+ @include styles-tokens-segmentedControl.composite-var(
44
+ styles-tokens-segmentedControl.$segmented-control,
45
+ 'background',
46
+ $size
47
+ );
44
48
  }
45
49
  }
46
50
  }
@@ -67,11 +71,18 @@ $sizes: 's', 'm', 'l';
67
71
 
68
72
  background-color: styles-tokens-segmentedControl.$sys-neutral-background2-level;
69
73
 
70
- transition: left 0.15s ease-in-out, width 0.15s ease-in-out;
74
+ transition:
75
+ left 0.15s ease-in-out,
76
+ width 0.15s ease-in-out;
71
77
 
72
78
  @each $size in $sizes {
73
79
  &[data-size='#{$size}'] {
74
- @include styles-tokens-segmentedControl.composite-var(styles-tokens-segmentedControl.$segmented-control, 'segment', $size, 'icon-only');
80
+ @include styles-tokens-segmentedControl.composite-var(
81
+ styles-tokens-segmentedControl.$segmented-control,
82
+ 'segment',
83
+ $size,
84
+ 'icon-only'
85
+ );
75
86
  }
76
87
  }
77
- }
88
+ }
package/src/constants.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export const SIZE = {
2
+ XS: 'xs',
2
3
  S: 's',
3
4
  M: 'm',
4
5
  L: 'l',
@@ -49,7 +49,7 @@ export function Segment({
49
49
  data-test-id={`section-${value}`}
50
50
  data-active={selected || undefined}
51
51
  data-disabled={disabled || undefined}
52
- data-layout={getLayout(icon, label)}
52
+ data-layout={getLayout(icon, label, size)}
53
53
  className={cn(styles.segment)}
54
54
  onClick={onClick}
55
55
  data-size={size}
@@ -59,7 +59,7 @@ export function Segment({
59
59
  role='radio'
60
60
  type='button'
61
61
  >
62
- {icon && <div className={styles.icon}>{icon}</div>}
62
+ {size !== 'xs' && icon && <div className={styles.icon}>{icon}</div>}
63
63
  {label && <TruncateString className={styles.label} data-size={size} text={label} />}
64
64
  </button>
65
65
  );
@@ -1,9 +1,10 @@
1
1
  @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-segmentedControl';
2
- @use "@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element";
2
+ @use '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
3
3
 
4
- $sizes: 's', 'm', 'l';
4
+ $sizes: 'xs', 's', 'm', 'l';
5
5
  $layouts: 'label-only', 'icon-before', 'icon-only';
6
6
  $typographies: (
7
+ 'xs': styles-tokens-segmentedControl.$sans-label-m,
7
8
  's': styles-tokens-segmentedControl.$sans-label-m,
8
9
  'm': styles-tokens-segmentedControl.$sans-label-m,
9
10
  'l': styles-tokens-segmentedControl.$sans-label-l,
@@ -29,7 +30,8 @@ $typographies: (
29
30
  color: styles-tokens-segmentedControl.$sys-neutral-text-main;
30
31
  }
31
32
 
32
- &[data-disabled], &[data-disabled]:hover {
33
+ &[data-disabled],
34
+ &[data-disabled]:hover {
33
35
  cursor: not-allowed;
34
36
  color: styles-tokens-segmentedControl.$sys-neutral-text-disabled;
35
37
  }
@@ -37,7 +39,8 @@ $typographies: (
37
39
  &[data-active] {
38
40
  color: styles-tokens-segmentedControl.$sys-neutral-text-main;
39
41
 
40
- &[data-disabled], &[data-disabled]:hover {
42
+ &[data-disabled],
43
+ &[data-disabled]:hover {
41
44
  color: styles-tokens-segmentedControl.$sys-neutral-text-disabled;
42
45
  }
43
46
  }
@@ -45,14 +48,21 @@ $typographies: (
45
48
  &:focus-visible {
46
49
  @include styles-tokens-segmentedControl.outline-inside-var(styles-tokens-element.$container-focused-s);
47
50
 
48
- outline-color: styles-tokens-segmentedControl.simple-var(styles-tokens-segmentedControl.$sys-available-complementary);
51
+ outline-color: styles-tokens-segmentedControl.simple-var(
52
+ styles-tokens-segmentedControl.$sys-available-complementary
53
+ );
49
54
  }
50
55
 
51
56
  @each $size in $sizes {
52
57
  &[data-size='#{$size}'] {
53
58
  @each $layout in $layouts {
54
59
  &[data-layout='#{$layout}'] {
55
- @include styles-tokens-segmentedControl.composite-var(styles-tokens-segmentedControl.$segmented-control, 'segment', $size, $layout);
60
+ @include styles-tokens-segmentedControl.composite-var(
61
+ styles-tokens-segmentedControl.$segmented-control,
62
+ 'segment',
63
+ $size,
64
+ $layout
65
+ );
56
66
  }
57
67
  }
58
68
  }
package/src/utils.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { ReactNode } from 'react';
2
2
 
3
- export const getLayout = (icon?: ReactNode, label?: string) => {
3
+ export const getLayout = (icon?: ReactNode, label?: string, size?: string) => {
4
+ if (size === 'xs') {
5
+ return 'label-only';
6
+ }
7
+
4
8
  if (icon && label) {
5
9
  return 'icon-before';
6
10
  }