@cloud-ru/ds-ai-queue 1.0.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/README.md +56 -0
  4. package/dist/cjs/AiQueue.d.ts +3 -0
  5. package/dist/cjs/AiQueue.js +29 -0
  6. package/dist/cjs/AiQueueStepStatus.d.ts +7 -0
  7. package/dist/cjs/AiQueueStepStatus.js +25 -0
  8. package/dist/cjs/constants.d.ts +15 -0
  9. package/dist/cjs/constants.js +22 -0
  10. package/dist/cjs/index.d.ts +3 -0
  11. package/dist/cjs/index.js +19 -0
  12. package/dist/cjs/package.json +3 -0
  13. package/dist/cjs/style.css +148 -0
  14. package/dist/cjs/styles.module.css +148 -0
  15. package/dist/cjs/types.d.ts +38 -0
  16. package/dist/cjs/types.js +2 -0
  17. package/dist/cjs/utils.d.ts +3 -0
  18. package/dist/cjs/utils.js +29 -0
  19. package/dist/esm/AiQueue.d.ts +3 -0
  20. package/dist/esm/AiQueue.js +23 -0
  21. package/dist/esm/AiQueueStepStatus.d.ts +7 -0
  22. package/dist/esm/AiQueueStepStatus.js +19 -0
  23. package/dist/esm/constants.d.ts +15 -0
  24. package/dist/esm/constants.js +19 -0
  25. package/dist/esm/index.d.ts +3 -0
  26. package/dist/esm/index.js +3 -0
  27. package/dist/esm/style.css +148 -0
  28. package/dist/esm/styles.module.css +148 -0
  29. package/dist/esm/types.d.ts +38 -0
  30. package/dist/esm/types.js +1 -0
  31. package/dist/esm/utils.d.ts +3 -0
  32. package/dist/esm/utils.js +25 -0
  33. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  34. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  35. package/package.json +45 -0
  36. package/src/AiQueue.tsx +84 -0
  37. package/src/AiQueueStepStatus.tsx +27 -0
  38. package/src/constants.ts +23 -0
  39. package/src/index.ts +3 -0
  40. package/src/styles.module.scss +145 -0
  41. package/src/types.ts +47 -0
  42. package/src/utils.ts +33 -0
@@ -0,0 +1,148 @@
1
+ .root{
2
+ position:relative;
3
+ display:flex;
4
+ flex-direction:column;
5
+ row-gap:0;
6
+ align-items:stretch;
7
+ width:100%;
8
+ padding-top:var(--sn-primitive-dimension-4, 4px);
9
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
10
+ }
11
+
12
+ .root[data-open]{
13
+ row-gap:var(--sn-primitive-dimension-8, 8px);
14
+ }
15
+
16
+ .trigger{
17
+ font-family:var(--sn-thin-label-s-fontFamily, var(--sn-brand-font-fontFamily-thin-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
18
+ font-weight:var(--sn-thin-label-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-label-s, var(--sn-brand-font-fontWeight-light-thin-label-s, var(--sn-primitive-font-fontWeightValue-450, 450))));
19
+ line-height:var(--sn-thin-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
20
+ font-size:var(--sn-thin-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
21
+ letter-spacing:var(--sn-thin-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
22
+ paragraph-spacing:var(--sn-thin-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
23
+ cursor:pointer;
24
+ display:flex;
25
+ -moz-column-gap:var(--sn-primitive-dimension-4, 4px);
26
+ column-gap:var(--sn-primitive-dimension-4, 4px);
27
+ align-items:center;
28
+ width:100%;
29
+ min-width:0;
30
+ margin:0;
31
+ padding:0;
32
+ border:0;
33
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
34
+ color:var(--sn-theme-color-available-version-textSecondary, var(--sn-brand-color-text-version-secondary, rgba(65, 66, 78, 0.8)));
35
+ text-align:left;
36
+ -webkit-appearance:none;
37
+ -moz-appearance:none;
38
+ appearance:none;
39
+ background:transparent;
40
+ outline:none;
41
+ }
42
+ .trigger:focus-visible{
43
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
44
+ outline-offset:0;
45
+ }
46
+
47
+ .summary{
48
+ overflow:hidden;
49
+ display:inline-flex;
50
+ -moz-column-gap:var(--sn-primitive-dimension-2, 2px);
51
+ column-gap:var(--sn-primitive-dimension-2, 2px);
52
+ align-items:center;
53
+ text-overflow:ellipsis;
54
+ white-space:nowrap;
55
+ }
56
+
57
+ .chevron{
58
+ flex-shrink:0;
59
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
60
+ }
61
+
62
+ .content{
63
+ max-height:140px;
64
+ }
65
+
66
+ .steps{
67
+ display:flex;
68
+ flex-direction:column;
69
+ row-gap:var(--sn-primitive-dimension-8, 8px);
70
+ align-items:stretch;
71
+ padding-right:var(--sn-primitive-dimension-8, 8px);
72
+ }
73
+
74
+ .step{
75
+ display:flex;
76
+ -moz-column-gap:var(--sn-primitive-dimension-4, 4px);
77
+ column-gap:var(--sn-primitive-dimension-4, 4px);
78
+ align-items:center;
79
+ width:100%;
80
+ min-width:0;
81
+ }
82
+
83
+ .stepStatus{
84
+ display:inline-flex;
85
+ flex-shrink:0;
86
+ align-items:center;
87
+ justify-content:center;
88
+ width:var(--sn-primitive-dimension-16, 16px);
89
+ height:var(--sn-primitive-dimension-16, 16px);
90
+ }
91
+
92
+ .stepStatusIcon{
93
+ width:100%;
94
+ height:100%;
95
+ }
96
+
97
+ .stepStatusSuccess{
98
+ color:var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
99
+ }
100
+
101
+ .stepStatusError{
102
+ color:var(--sn-theme-color-red-accent, var(--sn-primitive-color-red-55, #d52e33));
103
+ }
104
+
105
+ .stepStatusProgress{
106
+ color:var(--sn-theme-color-blue-accent, var(--sn-primitive-color-blue-55, #4387e2));
107
+ }
108
+
109
+ .stepStatusPending{
110
+ box-sizing:border-box;
111
+ width:var(--sn-primitive-dimension-8, 8px);
112
+ height:var(--sn-primitive-dimension-8, 8px);
113
+ border:var(--sn-primitive-strokeWeight-strokeRegular, 1px) solid var(--sn-theme-color-neutral-decor, var(--sn-brand-color-neutral-80, var(--sn-primitive-color-gray-80, #e3e5ed)));
114
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
115
+ }
116
+
117
+ .stepLabel{
118
+ font-family:var(--sn-thin-label-s-fontFamily, var(--sn-brand-font-fontFamily-thin-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
119
+ font-weight:var(--sn-thin-label-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-label-s, var(--sn-brand-font-fontWeight-light-thin-label-s, var(--sn-primitive-font-fontWeightValue-450, 450))));
120
+ line-height:var(--sn-thin-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
121
+ font-size:var(--sn-thin-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
122
+ letter-spacing:var(--sn-thin-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
123
+ paragraph-spacing:var(--sn-thin-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
124
+ overflow:hidden;
125
+ flex:1 1 auto;
126
+ min-width:0;
127
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
128
+ text-overflow:ellipsis;
129
+ white-space:nowrap;
130
+ }
131
+
132
+ .step[data-state=progress] .stepLabel{
133
+ font-family:var(--sn-regular-label-s-fontFamily, var(--sn-brand-font-fontFamily-regular-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
134
+ font-weight:var(--sn-regular-label-s-fontWeight, var(--sn-theme-typography-fontWeight-regular-label-s, var(--sn-brand-font-fontWeight-light-regular-label-s, var(--sn-primitive-font-fontWeightValue-500, 500))));
135
+ line-height:var(--sn-regular-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
136
+ font-size:var(--sn-regular-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
137
+ letter-spacing:var(--sn-regular-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
138
+ paragraph-spacing:var(--sn-regular-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
139
+ }
140
+
141
+ .step[data-state=error] .stepLabel,
142
+ .step[data-state=done] .stepLabel{
143
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
144
+ }
145
+
146
+ .step[data-state=done] .stepLabel{
147
+ text-decoration:line-through;
148
+ }
@@ -0,0 +1,38 @@
1
+ import { ValueOf, WithSupportProps } from '@cloud-ru/ds-utils';
2
+ import type { ComponentPropsWithoutRef } from 'react';
3
+ import { AI_QUEUE_STEP_STATE } from './constants';
4
+ export type AiQueueStepState = ValueOf<typeof AI_QUEUE_STEP_STATE>;
5
+ export type AiQueueStep = {
6
+ id?: string | number;
7
+ label: string;
8
+ state?: AiQueueStepState;
9
+ };
10
+ export type AiQueueSummary = {
11
+ total?: number;
12
+ planned?: number;
13
+ progress?: number;
14
+ done?: number;
15
+ };
16
+ export type AiQueueLabels = {
17
+ tasks: string;
18
+ planned: string;
19
+ inProgress: string;
20
+ done: string;
21
+ };
22
+ export type AiQueueOwnProps = {
23
+ /** Шаги очереди. */
24
+ steps?: AiQueueStep[];
25
+ /** Принудительные счётчики в заголовке; если не заданы, считаются по `steps`. */
26
+ summary?: AiQueueSummary;
27
+ /** Контролируемое состояние раскрытия. */
28
+ open?: boolean;
29
+ /** Начальное состояние раскрытия в uncontrolled-режиме. */
30
+ defaultOpen?: boolean;
31
+ /** Коллбек изменения раскрытия. */
32
+ onOpenChange?: (open: boolean) => void;
33
+ /** Тексты счётчика в заголовке. */
34
+ labels?: Partial<AiQueueLabels>;
35
+ /** Дополнительный CSS-класс корня. */
36
+ className?: string;
37
+ };
38
+ export type AiQueueProps = WithSupportProps<AiQueueOwnProps & Omit<ComponentPropsWithoutRef<'div'>, keyof AiQueueOwnProps | 'children'>>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,3 @@
1
+ import { AiQueueStep, AiQueueSummary } from './types';
2
+ export declare function resolveStepState(state?: AiQueueStep['state']): import("./types").AiQueueStepState;
3
+ export declare function calculateSummary(steps: AiQueueStep[]): Required<AiQueueSummary>;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveStepState = resolveStepState;
4
+ exports.calculateSummary = calculateSummary;
5
+ const constants_1 = require("./constants");
6
+ function resolveStepState(state) {
7
+ return state ?? constants_1.AI_QUEUE_STEP_STATE.Planned;
8
+ }
9
+ function calculateSummary(steps) {
10
+ return steps.reduce((acc, step) => {
11
+ const state = resolveStepState(step.state);
12
+ acc.total += 1;
13
+ if (state === constants_1.AI_QUEUE_STEP_STATE.Planned) {
14
+ acc.planned += 1;
15
+ }
16
+ if (state === constants_1.AI_QUEUE_STEP_STATE.Progress) {
17
+ acc.progress += 1;
18
+ }
19
+ if (state === constants_1.AI_QUEUE_STEP_STATE.Done) {
20
+ acc.done += 1;
21
+ }
22
+ return acc;
23
+ }, {
24
+ total: 0,
25
+ planned: 0,
26
+ progress: 0,
27
+ done: 0,
28
+ });
29
+ }
@@ -0,0 +1,3 @@
1
+ import { ReactElement } from 'react';
2
+ import { AiQueueProps } from './types.js';
3
+ export declare function AiQueue({ className, steps, summary, labels, open: openProp, defaultOpen, onOpenChange, 'data-test-id': dataTestId, ...rest }: AiQueueProps): ReactElement;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AiButtonChevron } from '@cloud-ru/ds-ai-button-chevron';
3
+ import { Scroll } from '@cloud-ru/ds-scroll';
4
+ import { useUncontrolledProp } from '@cloud-ru/ds-utils';
5
+ import cn from 'classnames';
6
+ import { useMemo } from 'react';
7
+ import { AiQueueStepStatus } from './AiQueueStepStatus.js';
8
+ import { DEFAULT_LABELS, TEST_IDS } from './constants.js';
9
+ import styles from './styles.module.css';
10
+ import { calculateSummary, resolveStepState } from './utils.js';
11
+ export function AiQueue({ className, steps = [], summary, labels, open: openProp, defaultOpen = false, onOpenChange, 'data-test-id': dataTestId = TEST_IDS.root, ...rest }) {
12
+ const [open, setOpen] = useUncontrolledProp(openProp, defaultOpen, onOpenChange);
13
+ const mergedLabels = { ...DEFAULT_LABELS, ...labels };
14
+ const derivedSummary = useMemo(() => calculateSummary(steps), [steps]);
15
+ const total = summary?.total ?? derivedSummary.total;
16
+ const planned = summary?.planned ?? derivedSummary.planned;
17
+ const progress = summary?.progress ?? derivedSummary.progress;
18
+ const done = summary?.done ?? derivedSummary.done;
19
+ return (_jsxs("div", { ...rest, className: cn(styles.root, className), "data-open": open || undefined, "data-test-id": dataTestId, children: [_jsxs("button", { type: 'button', className: styles.trigger, "aria-expanded": open, "data-test-id": TEST_IDS.trigger, onClick: () => setOpen(!open), children: [_jsxs("span", { className: styles.summary, "data-test-id": TEST_IDS.summary, children: [_jsx("span", { children: total }), _jsx("span", { children: mergedLabels.tasks }), _jsx("span", { children: "(" }), _jsx("span", { children: planned }), _jsx("span", { children: mergedLabels.planned }), _jsx("span", { children: "/" }), _jsx("span", { children: progress }), _jsx("span", { children: mergedLabels.inProgress }), _jsx("span", { children: "/" }), _jsx("span", { children: done }), _jsx("span", { children: mergedLabels.done }), _jsx("span", { children: ")" })] }), _jsx(AiButtonChevron, { opened: open, interactive: false, className: styles.chevron })] }), open && steps.length > 0 && (_jsx(Scroll, { size: 's', barHideStrategy: 'leave', className: styles.content, "data-test-id": TEST_IDS.content, children: _jsx("div", { className: styles.steps, children: steps.map((step, index) => {
20
+ const state = resolveStepState(step.state);
21
+ return (_jsxs("div", { className: styles.step, "data-state": state, "data-test-id": `${TEST_IDS.step}-${index}`, children: [_jsx("span", { className: styles.stepStatus, "aria-hidden": true, children: _jsx(AiQueueStepStatus, { state: state }) }), _jsx("span", { className: styles.stepLabel, children: step.label })] }, step.id ?? `${index}-${step.label}`));
22
+ }) }) }))] }));
23
+ }
@@ -0,0 +1,7 @@
1
+ import { ReactElement } from 'react';
2
+ import { AiQueueStepState } from './types.js';
3
+ type AiQueueStepStatusProps = {
4
+ state: AiQueueStepState;
5
+ };
6
+ export declare function AiQueueStepStatus({ state }: AiQueueStepStatusProps): ReactElement;
7
+ export {};
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { CheckSVG, CrossSVG } from '@cloud-ru/ds-icons/interface/system';
3
+ import { Sun, SUN_SIZE } from '@cloud-ru/ds-loader';
4
+ import cn from 'classnames';
5
+ import { AI_QUEUE_STEP_STATE } from './constants.js';
6
+ import styles from './styles.module.css';
7
+ const STEP_STATUS_ICON_SIZE = 16;
8
+ export function AiQueueStepStatus({ state }) {
9
+ switch (state) {
10
+ case AI_QUEUE_STEP_STATE.Done:
11
+ return _jsx(CheckSVG, { size: STEP_STATUS_ICON_SIZE, className: cn(styles.stepStatusIcon, styles.stepStatusSuccess) });
12
+ case AI_QUEUE_STEP_STATE.Error:
13
+ return _jsx(CrossSVG, { size: STEP_STATUS_ICON_SIZE, className: cn(styles.stepStatusIcon, styles.stepStatusError) });
14
+ case AI_QUEUE_STEP_STATE.Progress:
15
+ return _jsx(Sun, { size: SUN_SIZE.XS, className: cn(styles.stepStatusIcon, styles.stepStatusProgress) });
16
+ default:
17
+ return _jsx("span", { className: styles.stepStatusPending });
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ import type { AiQueueLabels } from './types.js';
2
+ export declare const AI_QUEUE_STEP_STATE: {
3
+ readonly Planned: "planned";
4
+ readonly Progress: "progress";
5
+ readonly Done: "done";
6
+ readonly Error: "error";
7
+ };
8
+ export declare const DEFAULT_LABELS: AiQueueLabels;
9
+ export declare const TEST_IDS: {
10
+ readonly root: "ai-queue";
11
+ readonly trigger: "ai-queue__trigger";
12
+ readonly summary: "ai-queue__summary";
13
+ readonly content: "ai-queue__content";
14
+ readonly step: "ai-queue__step";
15
+ };
@@ -0,0 +1,19 @@
1
+ export const AI_QUEUE_STEP_STATE = {
2
+ Planned: 'planned',
3
+ Progress: 'progress',
4
+ Done: 'done',
5
+ Error: 'error',
6
+ };
7
+ export const DEFAULT_LABELS = {
8
+ tasks: 'задач',
9
+ planned: 'запланировано',
10
+ inProgress: 'в процессе',
11
+ done: 'готово',
12
+ };
13
+ export const TEST_IDS = {
14
+ root: 'ai-queue',
15
+ trigger: 'ai-queue__trigger',
16
+ summary: 'ai-queue__summary',
17
+ content: 'ai-queue__content',
18
+ step: 'ai-queue__step',
19
+ };
@@ -0,0 +1,3 @@
1
+ export * from './AiQueue.js';
2
+ export * from './constants.js';
3
+ export * from './types.js';
@@ -0,0 +1,3 @@
1
+ export * from './AiQueue.js';
2
+ export * from './constants.js';
3
+ export * from './types.js';
@@ -0,0 +1,148 @@
1
+ .root{
2
+ position:relative;
3
+ display:flex;
4
+ flex-direction:column;
5
+ row-gap:0;
6
+ align-items:stretch;
7
+ width:100%;
8
+ padding-top:var(--sn-primitive-dimension-4, 4px);
9
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
10
+ }
11
+
12
+ .root[data-open]{
13
+ row-gap:var(--sn-primitive-dimension-8, 8px);
14
+ }
15
+
16
+ .trigger{
17
+ font-family:var(--sn-thin-label-s-fontFamily, var(--sn-brand-font-fontFamily-thin-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
18
+ font-weight:var(--sn-thin-label-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-label-s, var(--sn-brand-font-fontWeight-light-thin-label-s, var(--sn-primitive-font-fontWeightValue-450, 450))));
19
+ line-height:var(--sn-thin-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
20
+ font-size:var(--sn-thin-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
21
+ letter-spacing:var(--sn-thin-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
22
+ paragraph-spacing:var(--sn-thin-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
23
+ cursor:pointer;
24
+ display:flex;
25
+ -moz-column-gap:var(--sn-primitive-dimension-4, 4px);
26
+ column-gap:var(--sn-primitive-dimension-4, 4px);
27
+ align-items:center;
28
+ width:100%;
29
+ min-width:0;
30
+ margin:0;
31
+ padding:0;
32
+ border:0;
33
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
34
+ color:var(--sn-theme-color-available-version-textSecondary, var(--sn-brand-color-text-version-secondary, rgba(65, 66, 78, 0.8)));
35
+ text-align:left;
36
+ -webkit-appearance:none;
37
+ -moz-appearance:none;
38
+ appearance:none;
39
+ background:transparent;
40
+ outline:none;
41
+ }
42
+ .trigger:focus-visible{
43
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
44
+ outline-offset:0;
45
+ }
46
+
47
+ .summary{
48
+ overflow:hidden;
49
+ display:inline-flex;
50
+ -moz-column-gap:var(--sn-primitive-dimension-2, 2px);
51
+ column-gap:var(--sn-primitive-dimension-2, 2px);
52
+ align-items:center;
53
+ text-overflow:ellipsis;
54
+ white-space:nowrap;
55
+ }
56
+
57
+ .chevron{
58
+ flex-shrink:0;
59
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
60
+ }
61
+
62
+ .content{
63
+ max-height:140px;
64
+ }
65
+
66
+ .steps{
67
+ display:flex;
68
+ flex-direction:column;
69
+ row-gap:var(--sn-primitive-dimension-8, 8px);
70
+ align-items:stretch;
71
+ padding-right:var(--sn-primitive-dimension-8, 8px);
72
+ }
73
+
74
+ .step{
75
+ display:flex;
76
+ -moz-column-gap:var(--sn-primitive-dimension-4, 4px);
77
+ column-gap:var(--sn-primitive-dimension-4, 4px);
78
+ align-items:center;
79
+ width:100%;
80
+ min-width:0;
81
+ }
82
+
83
+ .stepStatus{
84
+ display:inline-flex;
85
+ flex-shrink:0;
86
+ align-items:center;
87
+ justify-content:center;
88
+ width:var(--sn-primitive-dimension-16, 16px);
89
+ height:var(--sn-primitive-dimension-16, 16px);
90
+ }
91
+
92
+ .stepStatusIcon{
93
+ width:100%;
94
+ height:100%;
95
+ }
96
+
97
+ .stepStatusSuccess{
98
+ color:var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
99
+ }
100
+
101
+ .stepStatusError{
102
+ color:var(--sn-theme-color-red-accent, var(--sn-primitive-color-red-55, #d52e33));
103
+ }
104
+
105
+ .stepStatusProgress{
106
+ color:var(--sn-theme-color-blue-accent, var(--sn-primitive-color-blue-55, #4387e2));
107
+ }
108
+
109
+ .stepStatusPending{
110
+ box-sizing:border-box;
111
+ width:var(--sn-primitive-dimension-8, 8px);
112
+ height:var(--sn-primitive-dimension-8, 8px);
113
+ border:var(--sn-primitive-strokeWeight-strokeRegular, 1px) solid var(--sn-theme-color-neutral-decor, var(--sn-brand-color-neutral-80, var(--sn-primitive-color-gray-80, #e3e5ed)));
114
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
115
+ }
116
+
117
+ .stepLabel{
118
+ font-family:var(--sn-thin-label-s-fontFamily, var(--sn-brand-font-fontFamily-thin-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
119
+ font-weight:var(--sn-thin-label-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-label-s, var(--sn-brand-font-fontWeight-light-thin-label-s, var(--sn-primitive-font-fontWeightValue-450, 450))));
120
+ line-height:var(--sn-thin-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
121
+ font-size:var(--sn-thin-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
122
+ letter-spacing:var(--sn-thin-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
123
+ paragraph-spacing:var(--sn-thin-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
124
+ overflow:hidden;
125
+ flex:1 1 auto;
126
+ min-width:0;
127
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
128
+ text-overflow:ellipsis;
129
+ white-space:nowrap;
130
+ }
131
+
132
+ .step[data-state=progress] .stepLabel{
133
+ font-family:var(--sn-regular-label-s-fontFamily, var(--sn-brand-font-fontFamily-regular-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
134
+ font-weight:var(--sn-regular-label-s-fontWeight, var(--sn-theme-typography-fontWeight-regular-label-s, var(--sn-brand-font-fontWeight-light-regular-label-s, var(--sn-primitive-font-fontWeightValue-500, 500))));
135
+ line-height:var(--sn-regular-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
136
+ font-size:var(--sn-regular-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
137
+ letter-spacing:var(--sn-regular-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
138
+ paragraph-spacing:var(--sn-regular-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
139
+ }
140
+
141
+ .step[data-state=error] .stepLabel,
142
+ .step[data-state=done] .stepLabel{
143
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
144
+ }
145
+
146
+ .step[data-state=done] .stepLabel{
147
+ text-decoration:line-through;
148
+ }
@@ -0,0 +1,148 @@
1
+ .root{
2
+ position:relative;
3
+ display:flex;
4
+ flex-direction:column;
5
+ row-gap:0;
6
+ align-items:stretch;
7
+ width:100%;
8
+ padding-top:var(--sn-primitive-dimension-4, 4px);
9
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
10
+ }
11
+
12
+ .root[data-open]{
13
+ row-gap:var(--sn-primitive-dimension-8, 8px);
14
+ }
15
+
16
+ .trigger{
17
+ font-family:var(--sn-thin-label-s-fontFamily, var(--sn-brand-font-fontFamily-thin-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
18
+ font-weight:var(--sn-thin-label-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-label-s, var(--sn-brand-font-fontWeight-light-thin-label-s, var(--sn-primitive-font-fontWeightValue-450, 450))));
19
+ line-height:var(--sn-thin-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
20
+ font-size:var(--sn-thin-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
21
+ letter-spacing:var(--sn-thin-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
22
+ paragraph-spacing:var(--sn-thin-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
23
+ cursor:pointer;
24
+ display:flex;
25
+ -moz-column-gap:var(--sn-primitive-dimension-4, 4px);
26
+ column-gap:var(--sn-primitive-dimension-4, 4px);
27
+ align-items:center;
28
+ width:100%;
29
+ min-width:0;
30
+ margin:0;
31
+ padding:0;
32
+ border:0;
33
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
34
+ color:var(--sn-theme-color-available-version-textSecondary, var(--sn-brand-color-text-version-secondary, rgba(65, 66, 78, 0.8)));
35
+ text-align:left;
36
+ -webkit-appearance:none;
37
+ -moz-appearance:none;
38
+ appearance:none;
39
+ background:transparent;
40
+ outline:none;
41
+ }
42
+ .trigger:focus-visible{
43
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
44
+ outline-offset:0;
45
+ }
46
+
47
+ .summary{
48
+ overflow:hidden;
49
+ display:inline-flex;
50
+ -moz-column-gap:var(--sn-primitive-dimension-2, 2px);
51
+ column-gap:var(--sn-primitive-dimension-2, 2px);
52
+ align-items:center;
53
+ text-overflow:ellipsis;
54
+ white-space:nowrap;
55
+ }
56
+
57
+ .chevron{
58
+ flex-shrink:0;
59
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
60
+ }
61
+
62
+ .content{
63
+ max-height:140px;
64
+ }
65
+
66
+ .steps{
67
+ display:flex;
68
+ flex-direction:column;
69
+ row-gap:var(--sn-primitive-dimension-8, 8px);
70
+ align-items:stretch;
71
+ padding-right:var(--sn-primitive-dimension-8, 8px);
72
+ }
73
+
74
+ .step{
75
+ display:flex;
76
+ -moz-column-gap:var(--sn-primitive-dimension-4, 4px);
77
+ column-gap:var(--sn-primitive-dimension-4, 4px);
78
+ align-items:center;
79
+ width:100%;
80
+ min-width:0;
81
+ }
82
+
83
+ .stepStatus{
84
+ display:inline-flex;
85
+ flex-shrink:0;
86
+ align-items:center;
87
+ justify-content:center;
88
+ width:var(--sn-primitive-dimension-16, 16px);
89
+ height:var(--sn-primitive-dimension-16, 16px);
90
+ }
91
+
92
+ .stepStatusIcon{
93
+ width:100%;
94
+ height:100%;
95
+ }
96
+
97
+ .stepStatusSuccess{
98
+ color:var(--sn-theme-color-primary-accent, var(--sn-brand-color-primary-55, var(--sn-brandRole-color-brandA-55, var(--sn-primitive-color-brandA-55, #389f74))));
99
+ }
100
+
101
+ .stepStatusError{
102
+ color:var(--sn-theme-color-red-accent, var(--sn-primitive-color-red-55, #d52e33));
103
+ }
104
+
105
+ .stepStatusProgress{
106
+ color:var(--sn-theme-color-blue-accent, var(--sn-primitive-color-blue-55, #4387e2));
107
+ }
108
+
109
+ .stepStatusPending{
110
+ box-sizing:border-box;
111
+ width:var(--sn-primitive-dimension-8, 8px);
112
+ height:var(--sn-primitive-dimension-8, 8px);
113
+ border:var(--sn-primitive-strokeWeight-strokeRegular, 1px) solid var(--sn-theme-color-neutral-decor, var(--sn-brand-color-neutral-80, var(--sn-primitive-color-gray-80, #e3e5ed)));
114
+ border-radius:var(--sn-density-radius-2xs, var(--sn-primitive-dimension-4, 4px));
115
+ }
116
+
117
+ .stepLabel{
118
+ font-family:var(--sn-thin-label-s-fontFamily, var(--sn-brand-font-fontFamily-thin-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
119
+ font-weight:var(--sn-thin-label-s-fontWeight, var(--sn-theme-typography-fontWeight-thin-label-s, var(--sn-brand-font-fontWeight-light-thin-label-s, var(--sn-primitive-font-fontWeightValue-450, 450))));
120
+ line-height:var(--sn-thin-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
121
+ font-size:var(--sn-thin-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
122
+ letter-spacing:var(--sn-thin-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
123
+ paragraph-spacing:var(--sn-thin-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
124
+ overflow:hidden;
125
+ flex:1 1 auto;
126
+ min-width:0;
127
+ color:var(--sn-theme-color-available-version-textMain, var(--sn-brand-color-text-version-main, #41424e));
128
+ text-overflow:ellipsis;
129
+ white-space:nowrap;
130
+ }
131
+
132
+ .step[data-state=progress] .stepLabel{
133
+ font-family:var(--sn-regular-label-s-fontFamily, var(--sn-brand-font-fontFamily-regular-label, var(--sn-primitive-fontFamily-brandA-sans, SB Sans Interface)));
134
+ font-weight:var(--sn-regular-label-s-fontWeight, var(--sn-theme-typography-fontWeight-regular-label-s, var(--sn-brand-font-fontWeight-light-regular-label-s, var(--sn-primitive-font-fontWeightValue-500, 500))));
135
+ line-height:var(--sn-regular-label-s-lineHeight, var(--sn-density-typography-roleLabel-lineHeightS, var(--sn-primitive-font-lineHeight-by14, 20px)));
136
+ font-size:var(--sn-regular-label-s-fontSize, var(--sn-density-typography-roleLabel-fontSizeS, var(--sn-primitive-font-fontSize-14, 14px)));
137
+ letter-spacing:var(--sn-regular-label-s-letterSpacing, var(--sn-primitive-font-letterSpacing-s, 0px));
138
+ paragraph-spacing:var(--sn-regular-label-s-paragraphSpacing, var(--sn-primitive-font-paragraphSpacing-byFontSize11, 5px));
139
+ }
140
+
141
+ .step[data-state=error] .stepLabel,
142
+ .step[data-state=done] .stepLabel{
143
+ color:var(--sn-theme-color-available-version-textTertiary, var(--sn-brand-color-text-version-tertiary, rgba(65, 66, 78, 0.5490196078)));
144
+ }
145
+
146
+ .step[data-state=done] .stepLabel{
147
+ text-decoration:line-through;
148
+ }
@@ -0,0 +1,38 @@
1
+ import { ValueOf, WithSupportProps } from '@cloud-ru/ds-utils';
2
+ import type { ComponentPropsWithoutRef } from 'react';
3
+ import { AI_QUEUE_STEP_STATE } from './constants.js';
4
+ export type AiQueueStepState = ValueOf<typeof AI_QUEUE_STEP_STATE>;
5
+ export type AiQueueStep = {
6
+ id?: string | number;
7
+ label: string;
8
+ state?: AiQueueStepState;
9
+ };
10
+ export type AiQueueSummary = {
11
+ total?: number;
12
+ planned?: number;
13
+ progress?: number;
14
+ done?: number;
15
+ };
16
+ export type AiQueueLabels = {
17
+ tasks: string;
18
+ planned: string;
19
+ inProgress: string;
20
+ done: string;
21
+ };
22
+ export type AiQueueOwnProps = {
23
+ /** Шаги очереди. */
24
+ steps?: AiQueueStep[];
25
+ /** Принудительные счётчики в заголовке; если не заданы, считаются по `steps`. */
26
+ summary?: AiQueueSummary;
27
+ /** Контролируемое состояние раскрытия. */
28
+ open?: boolean;
29
+ /** Начальное состояние раскрытия в uncontrolled-режиме. */
30
+ defaultOpen?: boolean;
31
+ /** Коллбек изменения раскрытия. */
32
+ onOpenChange?: (open: boolean) => void;
33
+ /** Тексты счётчика в заголовке. */
34
+ labels?: Partial<AiQueueLabels>;
35
+ /** Дополнительный CSS-класс корня. */
36
+ className?: string;
37
+ };
38
+ export type AiQueueProps = WithSupportProps<AiQueueOwnProps & Omit<ComponentPropsWithoutRef<'div'>, keyof AiQueueOwnProps | 'children'>>;
@@ -0,0 +1 @@
1
+ export {};