@drivenets/design-system 0.12.1 → 0.14.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 (122) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/index.cjs +1989 -735
  3. package/dist/index.d.cts +1378 -998
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.ts +1378 -998
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1978 -735
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.min.css +1 -1
  10. package/package.json +43 -41
  11. package/src/components/ds-button-v3/ds-button-v3.figma.ts +99 -0
  12. package/src/components/ds-button-v3/ds-button-v3.module.scss +22 -22
  13. package/src/components/ds-card/figma/ds-card-content.figma.ts +15 -0
  14. package/src/components/ds-card/figma/ds-card-footer.figma.ts +15 -0
  15. package/src/components/ds-card/figma/ds-card-header.figma.ts +15 -0
  16. package/src/components/ds-card/figma/ds-card.figma.ts +72 -0
  17. package/src/components/ds-date-input/ds-date-input.utils.ts +2 -2
  18. package/src/components/ds-date-picker/ds-date-picker.figma.ts +19 -0
  19. package/src/components/ds-drawer/ds-drawer.tsx +2 -0
  20. package/src/components/ds-form-control/ds-form-control.figma.ts +76 -0
  21. package/src/components/ds-form-control/ds-form-control.tsx +14 -11
  22. package/src/components/ds-form-control/ds-form-control.types.ts +4 -0
  23. package/src/components/ds-grid/ds-grid.tsx +1 -2
  24. package/src/components/ds-icon/figma/ds-icon-material.figma.batch.ts +10 -0
  25. package/src/components/ds-icon/figma/ds-icon-special.figma.batch.ts +18 -0
  26. package/src/components/ds-icon/figma/ds-icon.figma.batch.json +2873 -0
  27. package/src/components/ds-modal/ds-modal.tsx +3 -0
  28. package/src/components/ds-modal/figma/ds-modal-content.figma.ts +18 -0
  29. package/src/components/ds-modal/figma/ds-modal-footer.figma.ts +19 -0
  30. package/src/components/ds-modal/figma/ds-modal-header.figma.ts +21 -0
  31. package/src/components/ds-modal/figma/ds-modal.figma.ts +36 -0
  32. package/src/components/ds-popover/ds-popover.module.scss +58 -16
  33. package/src/components/ds-popover/ds-popover.tsx +148 -24
  34. package/src/components/ds-popover/ds-popover.types.ts +95 -12
  35. package/src/components/ds-popover/index.ts +1 -1
  36. package/src/components/ds-select/ds-select.figma.ts +53 -0
  37. package/src/components/ds-split-button/ds-split-button.figma.ts +95 -0
  38. package/src/components/ds-status-badge-v2/ds-status-badge-v2.figma.ts +41 -0
  39. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.module.scss +21 -2
  40. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.tsx +22 -14
  41. package/src/components/ds-table/components/ds-table-body-virtualized/ds-table-body-virtualized.types.ts +1 -6
  42. package/src/components/ds-table/components/ds-table-bulk-actions/ds-table-bulk-actions.module.scss +2 -2
  43. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.module.scss +2 -0
  44. package/src/components/ds-table/components/ds-table-cell/ds-table-cell.tsx +42 -11
  45. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.module.scss +31 -0
  46. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.tsx +48 -0
  47. package/src/components/ds-table/components/ds-table-group-header-cell/ds-table-group-header-cell.types.ts +12 -0
  48. package/src/components/ds-table/components/ds-table-group-header-cell/index.ts +2 -0
  49. package/src/components/ds-table/components/ds-table-header/ds-table-header.module.scss +28 -4
  50. package/src/components/ds-table/components/ds-table-header/ds-table-header.tsx +65 -28
  51. package/src/components/ds-table/components/ds-table-row/ds-table-row.module.scss +26 -0
  52. package/src/components/ds-table/components/ds-table-row/ds-table-row.tsx +3 -0
  53. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.module.scss +23 -0
  54. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.tsx +4 -1
  55. package/src/components/ds-table/components/ds-table-row-virtualized/ds-table-row-virtualized.types.ts +1 -1
  56. package/src/components/ds-table/components/edit/cell-editors/cell-editors.module.scss +3 -0
  57. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-checkbox.tsx +27 -0
  58. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-date.tsx +50 -0
  59. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-number.tsx +51 -0
  60. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-select.tsx +36 -0
  61. package/src/components/ds-table/components/edit/cell-editors/ds-table-edit-cell-text.tsx +50 -0
  62. package/src/components/ds-table/components/edit/cell-editors/index.ts +14 -0
  63. package/src/components/ds-table/components/edit/cell-editors/table-edit-form-control.tsx +31 -0
  64. package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.module.scss +28 -0
  65. package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.tsx +39 -0
  66. package/src/components/ds-table/components/edit/ds-table-editable-cell/ds-table-editable-cell.types.ts +7 -0
  67. package/src/components/ds-table/components/edit/ds-table-editable-cell/index.ts +2 -0
  68. package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.module.scss +48 -0
  69. package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.tsx +76 -0
  70. package/src/components/ds-table/components/edit/ds-table-editing-cell/ds-table-editing-cell.types.ts +5 -0
  71. package/src/components/ds-table/components/edit/ds-table-editing-cell/index.ts +2 -0
  72. package/src/components/ds-table/context/ds-table-context.ts +83 -1
  73. package/src/components/ds-table/ds-table-column.types.ts +12 -0
  74. package/src/components/ds-table/ds-table.module.scss +100 -10
  75. package/src/components/ds-table/ds-table.tsx +38 -21
  76. package/src/components/ds-table/ds-table.types.ts +107 -0
  77. package/src/components/ds-table/figma/ds-table-expandable.figma.ts +17 -0
  78. package/src/components/ds-table/figma/ds-table.figma.ts +16 -0
  79. package/src/components/ds-table/filters/adapters/create-checkbox-filter-adapter.tsx +24 -40
  80. package/src/components/ds-table/filters/adapters/create-dual-range-filter-adapter.tsx +10 -31
  81. package/src/components/ds-table/filters/adapters/create-filter-adapter.ts +6 -98
  82. package/src/components/ds-table/filters/components/checkbox-filter/checkbox-filter.module.scss +36 -0
  83. package/src/components/ds-table/filters/components/checkbox-filter/checkbox-filter.tsx +92 -13
  84. package/src/components/ds-table/filters/components/checkbox-filter/index.ts +1 -1
  85. package/src/components/ds-table/filters/components/column-filter-popover/column-filter-popover.module.scss +42 -0
  86. package/src/components/ds-table/filters/components/column-filter-popover/column-filter-popover.tsx +89 -0
  87. package/src/components/ds-table/filters/components/column-filter-popover/column-filter-popover.types.ts +25 -0
  88. package/src/components/ds-table/filters/components/column-filter-popover/index.ts +5 -0
  89. package/src/components/ds-table/filters/hooks/use-table-filters.ts +113 -78
  90. package/src/components/ds-table/filters/index.ts +2 -44
  91. package/src/components/ds-table/filters/types/column-meta.augmentation.ts +19 -0
  92. package/src/components/ds-table/filters/types/filter-adapter.types.ts +48 -81
  93. package/src/components/ds-table/grouping/hooks/use-column-groups.ts +73 -0
  94. package/src/components/ds-table/grouping/index.ts +5 -0
  95. package/src/components/ds-table/grouping/types/column-group-meta.augmentation.ts +26 -0
  96. package/src/components/ds-table/grouping/types/column-group.types.ts +35 -0
  97. package/src/components/ds-table/grouping/utils/column-group.ts +119 -0
  98. package/src/components/ds-table/hooks/use-cell-editor.ts +81 -0
  99. package/src/components/ds-table/index.ts +32 -0
  100. package/src/components/ds-table/styles/_variables.scss +1 -0
  101. package/src/components/ds-table/utils/column-size.ts +9 -8
  102. package/src/components/ds-tag/ds-tag.module.scss +22 -1
  103. package/src/components/ds-tag/ds-tag.tsx +18 -5
  104. package/src/components/ds-tag/ds-tag.types.ts +22 -8
  105. package/src/components/ds-tag/ds-tag.unit.test.ts +32 -0
  106. package/src/components/ds-tag-filter/ds-tag-filter.tsx +14 -22
  107. package/src/components/ds-text-input/ds-text-input.figma.ts +60 -0
  108. package/src/components/ds-time-picker/ds-time-picker.figma.ts +18 -0
  109. package/src/components/ds-workspace-layout/ds-workspace-layout.context.ts +19 -0
  110. package/src/components/ds-workspace-layout/ds-workspace-layout.module.scss +166 -0
  111. package/src/components/ds-workspace-layout/ds-workspace-layout.tsx +135 -0
  112. package/src/components/ds-workspace-layout/ds-workspace-layout.types.ts +52 -0
  113. package/src/components/ds-workspace-layout/index.ts +11 -0
  114. package/src/index.ts +1 -1
  115. package/src/styles/_root_new.scss +2 -0
  116. package/src/styles/_scrollbars.scss +36 -22
  117. package/src/utils/restore-document-body-modal-styles.ts +44 -0
  118. package/src/utils/use-ark-dialog-body-lock-cleanup.ts +36 -0
  119. package/src/components/ds-workspace/ds-workspace.module.scss +0 -55
  120. package/src/components/ds-workspace/ds-workspace.tsx +0 -37
  121. package/src/components/ds-workspace/ds-workspace.types.ts +0 -17
  122. package/src/components/ds-workspace/index.ts +0 -8
@@ -0,0 +1,166 @@
1
+ .root {
2
+ --ds-workspace-layout-header-height: 54px;
3
+ --ds-workspace-layout-header-gradient: radial-gradient(
4
+ ellipse at left bottom,
5
+ rgba(1, 75, 253, 1) 0%,
6
+ rgba(10, 60, 194, 1) 78%,
7
+ rgba(16, 51, 160, 1) 89%,
8
+ rgba(21, 42, 126, 1) 100%
9
+ );
10
+ --ds-workspace-layout-side-menu-collapsed-width: 60px;
11
+ --ds-workspace-layout-side-menu-expanded-width: 256px;
12
+ --ds-workspace-layout-side-menu-padding-top: 28px;
13
+ --ds-workspace-layout-side-menu-padding-x: 10px;
14
+ --ds-workspace-layout-content-margin-y: var(--lg);
15
+ --ds-workspace-layout-content-gap: var(--standard);
16
+ --ds-workspace-layout-content-margin-x: 40px;
17
+ --ds-workspace-layout-content-margin-x-with-left-panel: var(--lg);
18
+
19
+ display: flex;
20
+ flex-direction: column;
21
+ height: 100vh;
22
+ overflow: hidden;
23
+ background: var(--background);
24
+ }
25
+
26
+ .fillParent {
27
+ height: 100%;
28
+ }
29
+
30
+ .header {
31
+ display: flex;
32
+ align-items: center;
33
+ flex-shrink: 0;
34
+ height: var(--ds-workspace-layout-header-height);
35
+ padding: 0 var(--sm) 0 var(--lg);
36
+ background: var(--ds-workspace-layout-header-gradient);
37
+ color: var(--font-on-action);
38
+ overflow: clip;
39
+ }
40
+
41
+ .subHeader {
42
+ display: flex;
43
+ align-items: center;
44
+ flex-shrink: 0;
45
+ padding: var(--xs) var(--standard);
46
+ border-bottom: 1px solid var(--border);
47
+ background: var(--background);
48
+ }
49
+
50
+ .content {
51
+ display: flex;
52
+ flex: 1;
53
+ flex-direction: column;
54
+ gap: var(--ds-workspace-layout-content-gap);
55
+ min-width: 0;
56
+ min-height: 0;
57
+ position: relative;
58
+ padding: var(--ds-workspace-layout-content-margin-y) var(--ds-workspace-layout-content-margin-x);
59
+ overflow: auto;
60
+ }
61
+
62
+ .contentWithLeftPanel {
63
+ padding-inline: var(--ds-workspace-layout-content-margin-x-with-left-panel);
64
+ }
65
+
66
+ .footer {
67
+ display: flex;
68
+ align-items: center;
69
+ flex-shrink: 0;
70
+ padding: var(--xs) var(--standard);
71
+ border-top: 1px solid var(--border);
72
+ background: var(--background);
73
+ }
74
+
75
+ .body {
76
+ display: flex;
77
+ flex: 1;
78
+ min-height: 0;
79
+ overflow: hidden;
80
+ }
81
+
82
+ .sideMenu {
83
+ position: relative;
84
+ flex-shrink: 0;
85
+ min-width: 0;
86
+ height: 100%;
87
+ width: var(--ds-workspace-layout-side-menu-collapsed-width);
88
+ z-index: 100;
89
+
90
+ &[data-pinned] {
91
+ width: var(--ds-workspace-layout-side-menu-expanded-width);
92
+ }
93
+ }
94
+
95
+ .sideMenuPanel {
96
+ position: relative;
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: var(--xs);
100
+ height: 100%;
101
+ width: var(--ds-workspace-layout-side-menu-collapsed-width);
102
+ padding: var(--ds-workspace-layout-side-menu-padding-top) var(--ds-workspace-layout-side-menu-padding-x) 0;
103
+ overflow: hidden;
104
+ border-inline-end: 1px solid var(--border);
105
+ background: var(--background);
106
+ transition: width 0.2s;
107
+ }
108
+
109
+ .sideMenu[data-expanded] .sideMenuPanel {
110
+ width: var(--ds-workspace-layout-side-menu-expanded-width);
111
+ }
112
+
113
+ .sideMenu[data-expanded]:not([data-pinned]) .sideMenuPanel {
114
+ box-shadow: 0 4px 16px rgb(0 0 0 / 12%);
115
+ }
116
+
117
+ .sideMenuPinButton {
118
+ position: absolute;
119
+ top: var(--xs);
120
+ inset-inline-end: var(--xs);
121
+ display: flex;
122
+ align-items: center;
123
+ justify-content: center;
124
+ width: 24px;
125
+ height: 24px;
126
+ padding: 0;
127
+ border: none;
128
+ border-radius: var(--3xs);
129
+ background: transparent;
130
+ cursor: pointer;
131
+ color: var(--font-secondary);
132
+ opacity: 0;
133
+ visibility: hidden;
134
+ transition:
135
+ opacity 0.2s,
136
+ visibility 0.2s,
137
+ background-color 0.2s,
138
+ color 0.2s;
139
+
140
+ &:hover {
141
+ background: var(--background-action-tertiary-hover);
142
+ color: var(--font-action);
143
+ }
144
+
145
+ &[aria-pressed='true'] {
146
+ color: var(--font-action);
147
+ }
148
+
149
+ &:focus-visible {
150
+ outline: 2px solid var(--background-action);
151
+ outline-offset: 2px;
152
+ }
153
+ }
154
+
155
+ .sideMenu[data-expanded] .sideMenuPinButton {
156
+ opacity: 1;
157
+ visibility: visible;
158
+ }
159
+
160
+ .leftPanel {
161
+ display: flex;
162
+ flex-shrink: 0;
163
+ flex-direction: column;
164
+ min-height: 0;
165
+ height: 100%;
166
+ }
@@ -0,0 +1,135 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import classNames from 'classnames';
3
+ import styles from './ds-workspace-layout.module.scss';
4
+ import { DsWorkspaceLayoutContext, useDsWorkspaceLayoutContext } from './ds-workspace-layout.context';
5
+ import { DsIcon } from '../ds-icon';
6
+ import type {
7
+ DsWorkspaceLayoutProps,
8
+ DsWorkspaceLayoutHeaderProps,
9
+ DsWorkspaceLayoutSubHeaderProps,
10
+ DsWorkspaceLayoutContentProps,
11
+ DsWorkspaceLayoutFooterProps,
12
+ DsWorkspaceLayoutBodyProps,
13
+ DsWorkspaceLayoutSideMenuProps,
14
+ DsWorkspaceLayoutLeftPanelProps,
15
+ } from './ds-workspace-layout.types';
16
+
17
+ const DEFAULT_LOCALE = Object.freeze({
18
+ pinButtonLabel: 'Pin side menu',
19
+ unpinButtonLabel: 'Unpin side menu',
20
+ });
21
+
22
+ const DsWorkspaceLayout = ({ className, fillParent = false, ...rest }: DsWorkspaceLayoutProps) => {
23
+ const [hasLeftSidePanel, setHasLeftSidePanel] = useState(false);
24
+
25
+ const registerLeftSidePanel = useCallback(() => setHasLeftSidePanel(true), []);
26
+ const unregisterLeftSidePanel = useCallback(() => setHasLeftSidePanel(false), []);
27
+
28
+ const contextValue = useMemo(
29
+ () => ({ hasLeftSidePanel, registerLeftSidePanel, unregisterLeftSidePanel }),
30
+ [hasLeftSidePanel, registerLeftSidePanel, unregisterLeftSidePanel],
31
+ );
32
+
33
+ return (
34
+ <DsWorkspaceLayoutContext.Provider value={contextValue}>
35
+ <div {...rest} className={classNames(styles.root, { [styles.fillParent]: fillParent }, className)} />
36
+ </DsWorkspaceLayoutContext.Provider>
37
+ );
38
+ };
39
+
40
+ const Header = ({ className, ...rest }: DsWorkspaceLayoutHeaderProps) => (
41
+ <header {...rest} className={classNames(styles.header, className)} />
42
+ );
43
+
44
+ const SubHeader = ({ className, ...rest }: DsWorkspaceLayoutSubHeaderProps) => (
45
+ <div {...rest} className={classNames(styles.subHeader, className)} />
46
+ );
47
+
48
+ /** Content area: column layout, 24px vertical margins, 16px gap, 40px horizontal margins (24px when LeftPanel is mounted). */
49
+ const Content = ({ className, ...rest }: DsWorkspaceLayoutContentProps) => {
50
+ const { hasLeftSidePanel } = useDsWorkspaceLayoutContext();
51
+
52
+ return (
53
+ <div
54
+ {...rest}
55
+ className={classNames(styles.content, { [styles.contentWithLeftPanel]: hasLeftSidePanel }, className)}
56
+ />
57
+ );
58
+ };
59
+
60
+ const Footer = ({ className, ...rest }: DsWorkspaceLayoutFooterProps) => (
61
+ <footer {...rest} className={classNames(styles.footer, className)} />
62
+ );
63
+
64
+ const Body = ({ className, ...rest }: DsWorkspaceLayoutBodyProps) => {
65
+ useDsWorkspaceLayoutContext();
66
+
67
+ return <div {...rest} className={classNames(styles.body, className)} />;
68
+ };
69
+
70
+ const SideMenu = ({
71
+ className,
72
+ pinned = false,
73
+ onPinnedChange,
74
+ locale,
75
+ children,
76
+ ...rest
77
+ }: DsWorkspaceLayoutSideMenuProps) => {
78
+ useDsWorkspaceLayoutContext();
79
+ const [isHovering, setIsHovering] = useState(false);
80
+
81
+ const isExpanded = pinned || isHovering;
82
+ const ariaLabel = pinned
83
+ ? (locale?.unpinButtonLabel ?? DEFAULT_LOCALE.unpinButtonLabel)
84
+ : (locale?.pinButtonLabel ?? DEFAULT_LOCALE.pinButtonLabel);
85
+
86
+ return (
87
+ <aside
88
+ {...rest}
89
+ className={classNames(styles.sideMenu, className)}
90
+ {...(pinned ? { 'data-pinned': '' } : {})}
91
+ {...(isExpanded ? { 'data-expanded': '' } : {})}
92
+ >
93
+ <div
94
+ className={styles.sideMenuPanel}
95
+ onMouseEnter={() => setIsHovering(true)}
96
+ onMouseLeave={() => setIsHovering(false)}
97
+ >
98
+ {onPinnedChange ? (
99
+ <button
100
+ type="button"
101
+ className={styles.sideMenuPinButton}
102
+ onClick={() => onPinnedChange(!pinned)}
103
+ aria-label={ariaLabel}
104
+ aria-pressed={pinned}
105
+ >
106
+ <DsIcon icon="keep" size="small" filled={pinned} />
107
+ </button>
108
+ ) : null}
109
+ {children}
110
+ </div>
111
+ </aside>
112
+ );
113
+ };
114
+
115
+ const LeftPanel = ({ className, ...rest }: DsWorkspaceLayoutLeftPanelProps) => {
116
+ const { registerLeftSidePanel, unregisterLeftSidePanel } = useDsWorkspaceLayoutContext();
117
+
118
+ useEffect(() => {
119
+ registerLeftSidePanel();
120
+
121
+ return unregisterLeftSidePanel;
122
+ }, [registerLeftSidePanel, unregisterLeftSidePanel]);
123
+
124
+ return <aside {...rest} className={classNames(styles.leftPanel, className)} />;
125
+ };
126
+
127
+ DsWorkspaceLayout.Header = Header;
128
+ DsWorkspaceLayout.SubHeader = SubHeader;
129
+ DsWorkspaceLayout.Content = Content;
130
+ DsWorkspaceLayout.Footer = Footer;
131
+ DsWorkspaceLayout.Body = Body;
132
+ DsWorkspaceLayout.SideMenu = SideMenu;
133
+ DsWorkspaceLayout.LeftPanel = LeftPanel;
134
+
135
+ export default DsWorkspaceLayout;
@@ -0,0 +1,52 @@
1
+ import type { ComponentPropsWithRef } from 'react';
2
+
3
+ export interface DsWorkspaceLayoutProps extends ComponentPropsWithRef<'div'> {
4
+ /**
5
+ * Whether the workspace should fill its parent height (`100%`) instead of the viewport (`100vh`).
6
+ * @default false
7
+ */
8
+ fillParent?: boolean;
9
+ }
10
+
11
+ export type DsWorkspaceLayoutHeaderProps = ComponentPropsWithRef<'header'>;
12
+
13
+ export type DsWorkspaceLayoutSubHeaderProps = ComponentPropsWithRef<'div'>;
14
+
15
+ export type DsWorkspaceLayoutContentProps = ComponentPropsWithRef<'div'>;
16
+
17
+ export type DsWorkspaceLayoutFooterProps = ComponentPropsWithRef<'footer'>;
18
+
19
+ export type DsWorkspaceLayoutBodyProps = ComponentPropsWithRef<'div'>;
20
+
21
+ export type DsWorkspaceLayoutLeftPanelProps = ComponentPropsWithRef<'aside'>;
22
+
23
+ export interface DsWorkspaceLayoutSideMenuProps extends ComponentPropsWithRef<'aside'> {
24
+ /**
25
+ * Whether the side menu is pinned open. When `true`, the expanded panel pushes the content area
26
+ * to the right; when `false`, the collapsed rail is shown and hovering it overlays the expanded
27
+ * panel without shifting the content.
28
+ * @default false
29
+ */
30
+ pinned?: boolean;
31
+ /**
32
+ * Called when the built-in pin/unpin button is clicked. Pass this prop to render the pin
33
+ * affordance in the top-right corner of the expanded panel; omit it to hide the button (e.g.
34
+ * when the side menu should always remain in its default collapsed state).
35
+ */
36
+ onPinnedChange?: (pinned: boolean) => void;
37
+ /**
38
+ * Locale object (you can pass custom strings for localization).
39
+ */
40
+ locale?: {
41
+ /**
42
+ * aria-label for the pin button when the side menu is collapsed/unpinned.
43
+ * @default 'Pin side menu'
44
+ */
45
+ pinButtonLabel?: string;
46
+ /**
47
+ * aria-label for the pin button when the side menu is pinned.
48
+ * @default 'Unpin side menu'
49
+ */
50
+ unpinButtonLabel?: string;
51
+ };
52
+ }
@@ -0,0 +1,11 @@
1
+ export { default as DsWorkspaceLayout } from './ds-workspace-layout';
2
+ export type {
3
+ DsWorkspaceLayoutProps,
4
+ DsWorkspaceLayoutHeaderProps,
5
+ DsWorkspaceLayoutSubHeaderProps,
6
+ DsWorkspaceLayoutContentProps,
7
+ DsWorkspaceLayoutFooterProps,
8
+ DsWorkspaceLayoutBodyProps,
9
+ DsWorkspaceLayoutSideMenuProps,
10
+ DsWorkspaceLayoutLeftPanelProps,
11
+ } from './ds-workspace-layout.types';
package/src/index.ts CHANGED
@@ -64,5 +64,5 @@ export * from './components/ds-tooltip';
64
64
  export * from './components/ds-tree';
65
65
  export * from './components/ds-typography';
66
66
  export * from './components/ds-vertical-tabs';
67
- export * from './components/ds-workspace';
67
+ export * from './components/ds-workspace-layout';
68
68
  export * from './utils/responsive';
@@ -264,6 +264,7 @@
264
264
  --background-secondary-hover: var(--color-dap-blue-050);
265
265
  --background-secondary-selected-weak: var(--color-dap-gray-100);
266
266
  --background-success: var(--color-dap-green-075);
267
+ --background-success-medium: var(--color-dap-green-500);
267
268
  --background-success-strong: var(--color-dap-green-600);
268
269
  --background-success-strong-hover: var(--color-dap-green-700);
269
270
  --background-tertiary: var(--color-dap-gray-200);
@@ -327,6 +328,7 @@
327
328
  --icon-secondary: var(--color-dap-gray-600);
328
329
  --icon-success: var(--color-dap-green-700);
329
330
  --icon-success-light: var(--color-dap-green-400);
331
+ --icon-tertiary: var(--color-dap-brand-200);
330
332
  --icon-warning: var(--color-dap-orange-600);
331
333
  --icon-warning-light: var(--color-dap-orange-400);
332
334
  --light-buttons-primary: var(--color-dap-dark-blue-300);
@@ -1,46 +1,60 @@
1
1
  $scrollbar-border-radius: 100px;
2
- $scrollbar-default-size: 12px;
3
- $scrollbar-thin-size: 4px;
2
+ $scrollbar-default-size: 10px;
3
+ $scrollbar-hover-size: 12px;
4
+ $scrollbar-thin-size: 8px;
4
5
 
5
- @mixin scrollbar-base($size) {
6
+ @mixin scrollbar-auto-hide($rest-size, $hover-size) {
6
7
  &::-webkit-scrollbar {
7
- width: $size;
8
- height: $size;
9
- background: var(--background-secondary);
8
+ width: $rest-size;
9
+ height: $rest-size;
10
+ background: transparent;
10
11
  }
11
12
 
12
13
  &::-webkit-scrollbar-track {
13
- background: var(--background-secondary);
14
+ background: transparent;
15
+ }
16
+
17
+ &::-webkit-scrollbar-corner {
18
+ background: transparent;
14
19
  }
15
20
 
16
21
  &::-webkit-scrollbar-thumb {
17
- background: var(--background-deselected-hover);
22
+ background-color: var(--background-tertiary);
18
23
  border-radius: $scrollbar-border-radius;
24
+ transition: background-color 0.2s;
19
25
  }
20
26
 
21
- &::-webkit-scrollbar-corner {
22
- background: var(--background-secondary);
23
- }
24
- }
27
+ &:hover {
28
+ &::-webkit-scrollbar {
29
+ width: $hover-size;
30
+ height: $hover-size;
31
+ }
25
32
 
26
- @mixin firefox-scrollbar($size) {
27
- @-moz-document url-prefix() {
28
- @if $size == $scrollbar-thin-size {
29
- scrollbar-width: thin;
30
- } @else {
31
- scrollbar-width: auto;
33
+ &::-webkit-scrollbar-track {
34
+ background: var(--background-secondary);
32
35
  }
33
36
 
37
+ &::-webkit-scrollbar-thumb {
38
+ background-color: var(--background-deselected-hover);
39
+ }
40
+ }
41
+
42
+ scrollbar-width: thin;
43
+ scrollbar-color: var(--background-tertiary) transparent;
44
+
45
+ &:hover {
34
46
  scrollbar-color: var(--background-deselected-hover) var(--background-secondary);
35
47
  }
36
48
  }
37
49
 
50
+ @mixin scrollbar-on-hover {
51
+ @include scrollbar-auto-hide($scrollbar-default-size, $scrollbar-hover-size);
52
+ }
53
+
38
54
  * {
39
- @include scrollbar-base($scrollbar-default-size);
40
- @include firefox-scrollbar($scrollbar-default-size);
55
+ @include scrollbar-auto-hide($scrollbar-default-size, $scrollbar-hover-size);
41
56
  }
42
57
 
43
58
  .scrollbar-thin {
44
- @include scrollbar-base($scrollbar-thin-size);
45
- @include firefox-scrollbar($scrollbar-thin-size);
59
+ @include scrollbar-auto-hide($scrollbar-thin-size, $scrollbar-thin-size);
46
60
  }
@@ -0,0 +1,44 @@
1
+ const SCROLL_LOCK_ATTRIBUTE = 'data-scroll-lock';
2
+ const INERT_ATTRIBUTE = 'data-inert';
3
+ const ARIA_HIDDEN_MARKER = 'data-aria-hidden';
4
+
5
+ /**
6
+ * Clears document body styles and attributes left by Zag dialog modal effects when a
7
+ * dialog instance tears down without a normal close transition.
8
+ *
9
+ * No-op unless a leak sentinel is present: in the common case Zag restores the body on
10
+ * unmount itself, and we must not clobber styles the host app owns.
11
+ */
12
+ export const restoreDocumentBodyModalStyles = (doc: Document = document) => {
13
+ const { body, documentElement } = doc;
14
+
15
+ const hasLeakedLock =
16
+ body.hasAttribute(SCROLL_LOCK_ATTRIBUTE) ||
17
+ body.hasAttribute(INERT_ATTRIBUTE) ||
18
+ body.style.pointerEvents === 'none';
19
+
20
+ if (!hasLeakedLock) {
21
+ return;
22
+ }
23
+
24
+ body.removeAttribute(SCROLL_LOCK_ATTRIBUTE);
25
+ body.removeAttribute(INERT_ATTRIBUTE);
26
+ body.removeAttribute(ARIA_HIDDEN_MARKER);
27
+
28
+ if (body.getAttribute('aria-hidden') === 'true') {
29
+ body.removeAttribute('aria-hidden');
30
+ }
31
+
32
+ body.style.removeProperty('overflow');
33
+ body.style.removeProperty('pointer-events');
34
+ body.style.removeProperty('position');
35
+ body.style.removeProperty('top');
36
+ body.style.removeProperty('left');
37
+ body.style.removeProperty('right');
38
+
39
+ if (body.style.length === 0) {
40
+ body.removeAttribute('style');
41
+ }
42
+
43
+ documentElement.style.removeProperty('--scrollbar-width');
44
+ };
@@ -0,0 +1,36 @@
1
+ import { useLayoutEffect, useRef } from 'react';
2
+ import { restoreDocumentBodyModalStyles } from './restore-document-body-modal-styles';
3
+
4
+ const activeBodyLockInstances = new Set<symbol>();
5
+
6
+ const scheduleBodyLockRestoreIfIdle = () => {
7
+ queueMicrotask(() => {
8
+ if (activeBodyLockInstances.size > 0) {
9
+ return;
10
+ }
11
+
12
+ restoreDocumentBodyModalStyles();
13
+ });
14
+ };
15
+
16
+ /**
17
+ * Ensures Zag dialog body scroll-lock and modal pointer blocking are released when
18
+ * an Ark dialog unmounts while still open (e.g. close + conditional unmount + navigate).
19
+ */
20
+ export const useArkDialogBodyLockCleanup = (open: boolean, enabled: boolean) => {
21
+ const instanceIdRef = useRef(Symbol('ark-dialog-body-lock'));
22
+
23
+ useLayoutEffect(() => {
24
+ if (!open || !enabled) {
25
+ return;
26
+ }
27
+
28
+ const instanceId = instanceIdRef.current;
29
+ activeBodyLockInstances.add(instanceId);
30
+
31
+ return () => {
32
+ activeBodyLockInstances.delete(instanceId);
33
+ scheduleBodyLockRestoreIfIdle();
34
+ };
35
+ }, [open, enabled]);
36
+ };
@@ -1,55 +0,0 @@
1
- .root {
2
- --ds-workspace-header-height: 54px;
3
- --ds-workspace-header-gradient: radial-gradient(
4
- ellipse at left bottom,
5
- rgba(1, 75, 253, 1) 0%,
6
- rgba(10, 60, 194, 1) 78%,
7
- rgba(16, 51, 160, 1) 89%,
8
- rgba(21, 42, 126, 1) 100%
9
- );
10
-
11
- display: flex;
12
- flex-direction: column;
13
- height: 100vh;
14
- overflow: hidden;
15
- background: var(--background);
16
- }
17
-
18
- .fillParent {
19
- height: 100%;
20
- }
21
-
22
- .header {
23
- display: flex;
24
- align-items: center;
25
- flex-shrink: 0;
26
- height: var(--ds-workspace-header-height);
27
- padding: 0 var(--sm) 0 var(--lg);
28
- background: var(--ds-workspace-header-gradient);
29
- color: var(--font-on-action);
30
- overflow: clip;
31
- }
32
-
33
- .subHeader {
34
- display: flex;
35
- align-items: center;
36
- flex-shrink: 0;
37
- padding: var(--xs) var(--standard);
38
- border-bottom: 1px solid var(--border);
39
- background: var(--background);
40
- }
41
-
42
- .content {
43
- position: relative;
44
- flex: 1;
45
- overflow: auto;
46
- }
47
-
48
- .footer {
49
- display: flex;
50
- align-items: center;
51
- flex-shrink: 0;
52
- padding: var(--xs) var(--standard);
53
- border-top: 1px solid var(--border);
54
- background: var(--background);
55
- }
@@ -1,37 +0,0 @@
1
- import classNames from 'classnames';
2
- import styles from './ds-workspace.module.scss';
3
- import type {
4
- DsWorkspaceProps,
5
- DsWorkspaceHeaderProps,
6
- DsWorkspaceSubHeaderProps,
7
- DsWorkspaceContentProps,
8
- DsWorkspaceFooterProps,
9
- } from './ds-workspace.types';
10
-
11
- const DsWorkspace = ({ className, fillParent = false, ...rest }: DsWorkspaceProps) => (
12
- <div {...rest} className={classNames(styles.root, { [styles.fillParent]: fillParent }, className)} />
13
- );
14
-
15
- const Header = ({ className, ...rest }: DsWorkspaceHeaderProps) => (
16
- <header {...rest} className={classNames(styles.header, className)} />
17
- );
18
-
19
- const SubHeader = ({ className, ...rest }: DsWorkspaceSubHeaderProps) => (
20
- <div {...rest} className={classNames(styles.subHeader, className)} />
21
- );
22
-
23
- /** Stacking context for non-portal drawer containment. */
24
- const Content = ({ className, ...rest }: DsWorkspaceContentProps) => (
25
- <div {...rest} className={classNames(styles.content, className)} />
26
- );
27
-
28
- const Footer = ({ className, ...rest }: DsWorkspaceFooterProps) => (
29
- <footer {...rest} className={classNames(styles.footer, className)} />
30
- );
31
-
32
- DsWorkspace.Header = Header;
33
- DsWorkspace.SubHeader = SubHeader;
34
- DsWorkspace.Content = Content;
35
- DsWorkspace.Footer = Footer;
36
-
37
- export default DsWorkspace;
@@ -1,17 +0,0 @@
1
- import type { ComponentPropsWithRef } from 'react';
2
-
3
- export interface DsWorkspaceProps extends ComponentPropsWithRef<'div'> {
4
- /**
5
- * Whether the workspace should fill its parent height (`100%`) instead of the viewport (`100vh`).
6
- * @default false
7
- */
8
- fillParent?: boolean;
9
- }
10
-
11
- export type DsWorkspaceHeaderProps = ComponentPropsWithRef<'header'>;
12
-
13
- export type DsWorkspaceSubHeaderProps = ComponentPropsWithRef<'div'>;
14
-
15
- export type DsWorkspaceContentProps = ComponentPropsWithRef<'div'>;
16
-
17
- export type DsWorkspaceFooterProps = ComponentPropsWithRef<'footer'>;
@@ -1,8 +0,0 @@
1
- export { default as DsWorkspace } from './ds-workspace';
2
- export type {
3
- DsWorkspaceProps,
4
- DsWorkspaceHeaderProps,
5
- DsWorkspaceSubHeaderProps,
6
- DsWorkspaceContentProps,
7
- DsWorkspaceFooterProps,
8
- } from './ds-workspace.types';