@opencorestack/opengridx 0.1.6 → 0.1.7
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 +15 -0
- package/README.md +9 -0
- package/dist/index.d.ts +6 -0
- package/dist/opengridx.es.js +6 -6
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +4 -4
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +177 -0
- package/docs/README.md +60 -0
- package/docs/components/cell.md +44 -0
- package/docs/components/column-group-header.md +57 -0
- package/docs/components/column-resize.md +63 -0
- package/docs/components/column-visibility.md +61 -0
- package/docs/components/datagrid.md +70 -0
- package/docs/components/filter-panel.md +26 -0
- package/docs/components/header.md +39 -0
- package/docs/components/pagination.md +34 -0
- package/docs/components/row.md +31 -0
- package/docs/components/toolbar.md +40 -0
- package/docs/components/tooltip.md +68 -0
- package/docs/customization/slots-api.md +227 -0
- package/docs/customization/theming.md +293 -0
- package/docs/features/aggregation-pivot.md +79 -0
- package/docs/features/cell-spanning.md +520 -0
- package/docs/features/clipboard.md +76 -0
- package/docs/features/custom-pagination.md +143 -0
- package/docs/features/data-source.md +72 -0
- package/docs/features/editing-reordering.md +99 -0
- package/docs/features/export-guide.md +434 -0
- package/docs/features/filtering.md +83 -0
- package/docs/features/infinite-scroll.md +87 -0
- package/docs/features/list-view.md +65 -0
- package/docs/features/loading-states.md +68 -0
- package/docs/features/master-detail.md +46 -0
- package/docs/features/pinning.md +67 -0
- package/docs/features/selection.md +70 -0
- package/docs/features/sorting-pagination.md +66 -0
- package/docs/features/state-persistence.md +67 -0
- package/docs/features/tree-data-grouping.md +67 -0
- package/docs/features/virtualization.md +188 -0
- package/docs/roadmap.md +71 -0
- package/lib/components/Cell/Cell.css +119 -0
- package/lib/components/Cell/Cell.tsx +264 -0
- package/lib/components/Cell/GridEditInputCell.css +62 -0
- package/lib/components/Cell/GridEditInputCell.tsx +152 -0
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +67 -0
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +220 -0
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +31 -0
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +85 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +137 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +190 -0
- package/lib/components/DataGrid/DataGrid.css +224 -0
- package/lib/components/DataGrid/DataGrid.tsx +2253 -0
- package/lib/components/DetailPanel/DetailPanel.css +36 -0
- package/lib/components/DetailPanel/DetailPanel.tsx +34 -0
- package/lib/components/FilterPanel/FilterPanel.css +196 -0
- package/lib/components/FilterPanel/FilterPanel.tsx +183 -0
- package/lib/components/FilterPanel/index.ts +1 -0
- package/lib/components/Header/ColumnMenu.css +68 -0
- package/lib/components/Header/ColumnMenu.tsx +249 -0
- package/lib/components/Header/Header.css +224 -0
- package/lib/components/Header/Header.tsx +516 -0
- package/lib/components/ListView/ListView.css +112 -0
- package/lib/components/ListView/ListViewRow.tsx +63 -0
- package/lib/components/Pagination/Pagination.css +91 -0
- package/lib/components/Pagination/Pagination.tsx +151 -0
- package/lib/components/QuickFilter/QuickFilter.css +23 -0
- package/lib/components/QuickFilter/QuickFilter.tsx +79 -0
- package/lib/components/Row/Row.css +126 -0
- package/lib/components/Row/Row.tsx +377 -0
- package/lib/components/Skeleton/Skeleton.css +55 -0
- package/lib/components/Skeleton/Skeleton.tsx +22 -0
- package/lib/components/SkeletonRow/SkeletonRow.css +32 -0
- package/lib/components/SkeletonRow/SkeletonRow.tsx +89 -0
- package/lib/components/SkeletonRow/index.ts +1 -0
- package/lib/components/Toolbar/GlobalSearch.css +113 -0
- package/lib/components/Toolbar/GlobalSearch.tsx +120 -0
- package/lib/components/Toolbar/GridToolbar.css +204 -0
- package/lib/components/Toolbar/GridToolbar.tsx +647 -0
- package/lib/components/Toolbar/PivotPanel.css +212 -0
- package/lib/components/Toolbar/PivotPanel.tsx +239 -0
- package/lib/components/Tooltip/Tooltip.css +59 -0
- package/lib/components/Tooltip/Tooltip.tsx +106 -0
- package/lib/components/ui/Button.css +89 -0
- package/lib/components/ui/Button.tsx +39 -0
- package/lib/components/ui/Checkbox.css +71 -0
- package/lib/components/ui/Checkbox.tsx +66 -0
- package/lib/components/ui/DragHandleIcon.css +19 -0
- package/lib/components/ui/DragHandleIcon.tsx +18 -0
- package/lib/components/ui/ExpandIcon.css +38 -0
- package/lib/components/ui/ExpandIcon.tsx +75 -0
- package/lib/components/ui/Input.css +59 -0
- package/lib/components/ui/Input.tsx +45 -0
- package/lib/components/ui/index.ts +15 -0
- package/lib/hooks/core/useDataGrid.ts +392 -0
- package/lib/hooks/core/useGridApiRef.ts +10 -0
- package/lib/hooks/features/useAggregation.ts +143 -0
- package/lib/hooks/features/useGridClipboard.ts +133 -0
- package/lib/hooks/features/useGridDataSource.ts +190 -0
- package/lib/hooks/features/useGridEditing.ts +100 -0
- package/lib/hooks/features/useGridSpanning.ts +349 -0
- package/lib/hooks/features/usePivot.ts +149 -0
- package/lib/hooks/useColumnReorder.ts +114 -0
- package/lib/hooks/useRowGrouping.ts +302 -0
- package/lib/hooks/useRowReorder.ts +83 -0
- package/lib/hooks/useTreeData.ts +323 -0
- package/lib/index.ts +106 -0
- package/lib/state/index.ts +17 -0
- package/lib/state/types.ts +48 -0
- package/lib/state/useGridStateStorage.ts +113 -0
- package/lib/styles/base/reset.css +21 -0
- package/lib/styles/base/variables.css +161 -0
- package/lib/styles/opengridx.css +27 -0
- package/lib/styles/opengridx.css.d.ts +4 -0
- package/lib/theme/DataGridThemeProvider.tsx +276 -0
- package/lib/theme/defaultStyles.ts +0 -0
- package/lib/theme/index.ts +21 -0
- package/lib/theme/presets.ts +148 -0
- package/lib/theme/types.ts +155 -0
- package/lib/types/index.ts +764 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +516 -0
- package/lib/utils/export/index.ts +550 -0
- package/lib/utils/filtering/index.ts +240 -0
- package/lib/utils/pinning/index.ts +282 -0
- package/lib/utils/sorting/index.ts +55 -0
- package/lib/utils/virtualization/index.ts +106 -0
- package/lib/vite-env.d.ts +1 -0
- package/llms.txt +2 -1
- package/package.json +13 -4
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
.ogx-button {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
font-family: var(--ogx-font-family);
|
|
6
|
+
font-weight: var(--ogx-font-weight-medium);
|
|
7
|
+
line-height: var(--ogx-line-height-normal);
|
|
8
|
+
border-radius: var(--ogx-border-radius-md);
|
|
9
|
+
transition: all var(--ogx-transition-duration-fast) var(--ogx-transition-easing);
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
user-select: none;
|
|
12
|
+
}
|
|
13
|
+
.ogx-button--small {
|
|
14
|
+
padding: var(--ogx-spacing-xs) var(--ogx-spacing-sm);
|
|
15
|
+
font-size: var(--ogx-font-size-sm);
|
|
16
|
+
min-height: 28px;
|
|
17
|
+
}
|
|
18
|
+
.ogx-button--medium {
|
|
19
|
+
padding: var(--ogx-spacing-sm) var(--ogx-spacing-md);
|
|
20
|
+
font-size: var(--ogx-font-size-md);
|
|
21
|
+
min-height: 36px;
|
|
22
|
+
}
|
|
23
|
+
.ogx-button--large {
|
|
24
|
+
padding: var(--ogx-spacing-md) var(--ogx-spacing-lg);
|
|
25
|
+
font-size: var(--ogx-font-size-lg);
|
|
26
|
+
min-height: 44px;
|
|
27
|
+
}
|
|
28
|
+
.ogx-button--text {
|
|
29
|
+
background: transparent;
|
|
30
|
+
border: none;
|
|
31
|
+
color: var(--ogx-grid-row-text);
|
|
32
|
+
}
|
|
33
|
+
.ogx-button--text.ogx-button--primary {
|
|
34
|
+
color: var(--ogx-color-primary);
|
|
35
|
+
}
|
|
36
|
+
.ogx-button--text.ogx-button--secondary {
|
|
37
|
+
color: var(--ogx-color-secondary);
|
|
38
|
+
}
|
|
39
|
+
.ogx-button--text:hover:not(.ogx-button--disabled) {
|
|
40
|
+
background: var(--ogx-grid-header-hover-background, var(--ogx-color-gray-100));
|
|
41
|
+
}
|
|
42
|
+
.ogx-button--text.ogx-button--primary:hover:not(.ogx-button--disabled) {
|
|
43
|
+
background: var(--ogx-color-primary-light);
|
|
44
|
+
}
|
|
45
|
+
.ogx-button--outlined {
|
|
46
|
+
background: transparent;
|
|
47
|
+
border: var(--ogx-border-width-thin) solid var(--ogx-border-color);
|
|
48
|
+
color: var(--ogx-grid-row-text);
|
|
49
|
+
}
|
|
50
|
+
.ogx-button--outlined.ogx-button--primary {
|
|
51
|
+
border-color: var(--ogx-color-primary);
|
|
52
|
+
color: var(--ogx-color-primary);
|
|
53
|
+
}
|
|
54
|
+
.ogx-button--outlined.ogx-button--secondary {
|
|
55
|
+
border-color: var(--ogx-color-secondary);
|
|
56
|
+
color: var(--ogx-color-secondary);
|
|
57
|
+
}
|
|
58
|
+
.ogx-button--outlined:hover:not(.ogx-button--disabled) {
|
|
59
|
+
background: var(--ogx-grid-header-hover-background, var(--ogx-color-gray-100));
|
|
60
|
+
border-color: var(--ogx-border-color-hover);
|
|
61
|
+
}
|
|
62
|
+
.ogx-button--contained {
|
|
63
|
+
background: var(--ogx-color-gray-200);
|
|
64
|
+
border: none;
|
|
65
|
+
color: var(--ogx-grid-row-text);
|
|
66
|
+
}
|
|
67
|
+
.ogx-button--contained.ogx-button--primary {
|
|
68
|
+
background: var(--ogx-color-primary);
|
|
69
|
+
color: var(--ogx-color-white);
|
|
70
|
+
}
|
|
71
|
+
.ogx-button--contained.ogx-button--secondary {
|
|
72
|
+
background: var(--ogx-color-secondary);
|
|
73
|
+
color: var(--ogx-color-white);
|
|
74
|
+
}
|
|
75
|
+
.ogx-button--contained:hover:not(.ogx-button--disabled) {
|
|
76
|
+
background: var(--ogx-color-gray-300);
|
|
77
|
+
}
|
|
78
|
+
.ogx-button--contained.ogx-button--primary:hover:not(.ogx-button--disabled) {
|
|
79
|
+
background: var(--ogx-color-primary-dark);
|
|
80
|
+
}
|
|
81
|
+
.ogx-button--disabled {
|
|
82
|
+
opacity: 0.5;
|
|
83
|
+
cursor: not-allowed;
|
|
84
|
+
pointer-events: none;
|
|
85
|
+
}
|
|
86
|
+
.ogx-button:focus-visible {
|
|
87
|
+
outline: 2px solid var(--ogx-color-primary);
|
|
88
|
+
outline-offset: 2px;
|
|
89
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
|
+
variant?: 'text' | 'outlined' | 'contained';
|
|
6
|
+
size?: 'small' | 'medium' | 'large';
|
|
7
|
+
color?: 'primary' | 'secondary' | 'default';
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Button: React.FC<ButtonProps> = ({
|
|
13
|
+
variant = 'text',
|
|
14
|
+
size = 'medium',
|
|
15
|
+
color = 'default',
|
|
16
|
+
disabled = false,
|
|
17
|
+
className = '',
|
|
18
|
+
children,
|
|
19
|
+
...props
|
|
20
|
+
}) => {
|
|
21
|
+
const classNames = [
|
|
22
|
+
'ogx-button',
|
|
23
|
+
`ogx-button--${variant}`,
|
|
24
|
+
`ogx-button--${size}`,
|
|
25
|
+
`ogx-button--${color}`,
|
|
26
|
+
disabled && 'ogx-button--disabled',
|
|
27
|
+
className
|
|
28
|
+
].filter(Boolean).join(' ');
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<button
|
|
32
|
+
className={classNames}
|
|
33
|
+
disabled={disabled}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</button>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
.ogx-checkbox-wrapper {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
cursor: pointer;
|
|
5
|
+
user-select: none;
|
|
6
|
+
font-family: var(--ogx-font-family);
|
|
7
|
+
}
|
|
8
|
+
.ogx-checkbox-wrapper--disabled {
|
|
9
|
+
opacity: 0.6;
|
|
10
|
+
cursor: not-allowed;
|
|
11
|
+
}
|
|
12
|
+
.ogx-checkbox__input {
|
|
13
|
+
appearance: none;
|
|
14
|
+
position: absolute;
|
|
15
|
+
opacity: 0;
|
|
16
|
+
width: 0;
|
|
17
|
+
height: 0;
|
|
18
|
+
}
|
|
19
|
+
.ogx-checkbox__box {
|
|
20
|
+
display: inline-flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
justify-content: center;
|
|
23
|
+
width: 18px;
|
|
24
|
+
height: 18px;
|
|
25
|
+
border: 1.5px solid var(--ogx-checkbox-border, var(--ogx-color-gray-400));
|
|
26
|
+
border-radius: 4px;
|
|
27
|
+
background: var(--ogx-checkbox-bg, var(--ogx-color-white));
|
|
28
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
29
|
+
color: white;
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
}
|
|
32
|
+
.ogx-checkbox__icon {
|
|
33
|
+
width: 12px;
|
|
34
|
+
height: 12px;
|
|
35
|
+
fill: currentColor;
|
|
36
|
+
transform: scale(0);
|
|
37
|
+
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
38
|
+
}
|
|
39
|
+
.ogx-checkbox__label {
|
|
40
|
+
margin-left: var(--ogx-spacing-sm);
|
|
41
|
+
font-size: var(--ogx-font-size-sm);
|
|
42
|
+
color: var(--ogx-grid-row-text, var(--ogx-color-gray-700));
|
|
43
|
+
line-height: 1;
|
|
44
|
+
}
|
|
45
|
+
.ogx-checkbox__input:checked + .ogx-checkbox__box {
|
|
46
|
+
background: var(--ogx-color-primary);
|
|
47
|
+
border-color: var(--ogx-color-primary);
|
|
48
|
+
}
|
|
49
|
+
.ogx-checkbox__input:checked + .ogx-checkbox__box .ogx-checkbox__icon {
|
|
50
|
+
transform: scale(1);
|
|
51
|
+
}
|
|
52
|
+
.ogx-checkbox__input:indeterminate + .ogx-checkbox__box {
|
|
53
|
+
background: var(--ogx-color-primary);
|
|
54
|
+
border-color: var(--ogx-color-primary);
|
|
55
|
+
}
|
|
56
|
+
.ogx-checkbox__input:indeterminate + .ogx-checkbox__box .ogx-checkbox__icon {
|
|
57
|
+
transform: scale(1);
|
|
58
|
+
}
|
|
59
|
+
.ogx-checkbox-wrapper:hover:not(.ogx-checkbox-wrapper--disabled) .ogx-checkbox__box {
|
|
60
|
+
border-color: var(--ogx-color-primary);
|
|
61
|
+
box-shadow: 0 0 0 4px var(--ogx-color-primary-light);
|
|
62
|
+
}
|
|
63
|
+
.ogx-checkbox__input:focus-visible + .ogx-checkbox__box {
|
|
64
|
+
border-color: var(--ogx-color-primary);
|
|
65
|
+
box-shadow: 0 0 0 4px var(--ogx-color-primary-focus);
|
|
66
|
+
}
|
|
67
|
+
.ogx-checkbox-wrapper--disabled .ogx-checkbox__box {
|
|
68
|
+
background: var(--ogx-color-gray-100);
|
|
69
|
+
border-color: var(--ogx-color-gray-300);
|
|
70
|
+
color: var(--ogx-color-gray-400);
|
|
71
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'type'> {
|
|
5
|
+
indeterminate?: boolean;
|
|
6
|
+
label?: string;
|
|
7
|
+
inputRef?: React.Ref<HTMLInputElement>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Checkbox: React.FC<CheckboxProps> = ({
|
|
11
|
+
indeterminate = false,
|
|
12
|
+
label,
|
|
13
|
+
className = '',
|
|
14
|
+
inputRef,
|
|
15
|
+
...props
|
|
16
|
+
}) => {
|
|
17
|
+
const internalRef = React.useRef<HTMLInputElement>(null);
|
|
18
|
+
|
|
19
|
+
// Combine refs
|
|
20
|
+
const setRef = React.useCallback((element: HTMLInputElement | null) => {
|
|
21
|
+
internalRef.current = element;
|
|
22
|
+
|
|
23
|
+
if (typeof inputRef === 'function') {
|
|
24
|
+
inputRef(element);
|
|
25
|
+
} else if (inputRef) {
|
|
26
|
+
(inputRef as React.MutableRefObject<HTMLInputElement | null>).current = element;
|
|
27
|
+
}
|
|
28
|
+
}, [inputRef]);
|
|
29
|
+
|
|
30
|
+
React.useEffect(() => {
|
|
31
|
+
if (internalRef.current) {
|
|
32
|
+
internalRef.current.indeterminate = indeterminate;
|
|
33
|
+
}
|
|
34
|
+
}, [indeterminate]);
|
|
35
|
+
|
|
36
|
+
const wrapperClassNames = [
|
|
37
|
+
'ogx-checkbox-wrapper',
|
|
38
|
+
props.disabled && 'ogx-checkbox-wrapper--disabled',
|
|
39
|
+
className
|
|
40
|
+
].filter(Boolean).join(' ');
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<label className={wrapperClassNames}>
|
|
44
|
+
<input
|
|
45
|
+
ref={setRef}
|
|
46
|
+
type="checkbox"
|
|
47
|
+
className="ogx-checkbox__input"
|
|
48
|
+
aria-label={label || props['aria-label'] || (indeterminate ? 'Select some' : props.checked ? 'Deselect' : 'Select')}
|
|
49
|
+
{...props}
|
|
50
|
+
/>
|
|
51
|
+
<span className="ogx-checkbox__box">
|
|
52
|
+
{props.checked && !indeterminate && (
|
|
53
|
+
<svg className="ogx-checkbox__icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
54
|
+
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
|
|
55
|
+
</svg>
|
|
56
|
+
)}
|
|
57
|
+
{indeterminate && (
|
|
58
|
+
<svg className="ogx-checkbox__icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
59
|
+
<path d="M19 13H5v-2h14v2z" />
|
|
60
|
+
</svg>
|
|
61
|
+
)}
|
|
62
|
+
</span>
|
|
63
|
+
{label && <span className="ogx-checkbox__label">{label}</span>}
|
|
64
|
+
</label>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
.ogx-drag-handle {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
cursor: grab;
|
|
6
|
+
color: var(--ogx-grid-header-text);
|
|
7
|
+
padding: 0 4px;
|
|
8
|
+
opacity: 0.5;
|
|
9
|
+
transition: opacity 0.2s, color 0.2s;
|
|
10
|
+
}
|
|
11
|
+
.ogx-drag-handle:hover {
|
|
12
|
+
opacity: 1;
|
|
13
|
+
color: var(--ogx-grid-row-text);
|
|
14
|
+
}
|
|
15
|
+
.ogx-drag-handle:active {
|
|
16
|
+
cursor: grabbing;
|
|
17
|
+
color: var(--ogx-color-primary);
|
|
18
|
+
opacity: 1;
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface DragHandleIconProps extends React.ButtonHTMLAttributes<HTMLButtonElement> { }
|
|
4
|
+
|
|
5
|
+
export const DragHandleIcon: React.FC<DragHandleIconProps> = ({ className = '', ...props }) => {
|
|
6
|
+
return (
|
|
7
|
+
<button
|
|
8
|
+
type="button"
|
|
9
|
+
className={`ogx-drag-handle ${className}`}
|
|
10
|
+
aria-label="Drag to reorder row"
|
|
11
|
+
{...props}
|
|
12
|
+
>
|
|
13
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true">
|
|
14
|
+
<path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" />
|
|
15
|
+
</svg>
|
|
16
|
+
</button>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
.ogx-expand-icon {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: center;
|
|
5
|
+
width: 24px;
|
|
6
|
+
height: 24px;
|
|
7
|
+
padding: 0;
|
|
8
|
+
border: none;
|
|
9
|
+
background: transparent;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
color: var(--ogx-grid-header-text);
|
|
12
|
+
transition: color 0.2s ease;
|
|
13
|
+
border-radius: 4px;
|
|
14
|
+
}
|
|
15
|
+
.ogx-expand-icon:hover {
|
|
16
|
+
background: transparent;
|
|
17
|
+
color: var(--ogx-grid-row-text);
|
|
18
|
+
}
|
|
19
|
+
.ogx-expand-icon:focus {
|
|
20
|
+
outline: none;
|
|
21
|
+
}
|
|
22
|
+
.ogx-expand-icon:focus-visible {
|
|
23
|
+
outline: 2px solid var(--ogx-color-primary);
|
|
24
|
+
outline-offset: 2px;
|
|
25
|
+
}
|
|
26
|
+
.ogx-expand-icon svg {
|
|
27
|
+
display: block;
|
|
28
|
+
transition: transform 0.2s ease;
|
|
29
|
+
}
|
|
30
|
+
@media (prefers-color-scheme: dark) {
|
|
31
|
+
.ogx-expand-icon {
|
|
32
|
+
color: var(--ogx-color-gray-400);
|
|
33
|
+
}
|
|
34
|
+
.ogx-expand-icon:hover {
|
|
35
|
+
background: var(--ogx-color-gray-800);
|
|
36
|
+
color: var(--ogx-color-gray-100);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface ExpandIconProps {
|
|
5
|
+
isExpanded: boolean;
|
|
6
|
+
onClick?: (event: React.MouseEvent) => void;
|
|
7
|
+
variant?: 'chevron' | 'plus-minus';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ExpandIcon({ isExpanded, onClick, variant = 'chevron' }: ExpandIconProps) {
|
|
11
|
+
return (
|
|
12
|
+
<button
|
|
13
|
+
className={`ogx-expand-icon ${isExpanded ? 'ogx-expand-icon--expanded' : ''}`}
|
|
14
|
+
onClick={(e) => {
|
|
15
|
+
if (onClick) {
|
|
16
|
+
onClick(e);
|
|
17
|
+
}
|
|
18
|
+
}}
|
|
19
|
+
aria-label={isExpanded ? 'Collapse row' : 'Expand row'}
|
|
20
|
+
type="button"
|
|
21
|
+
>
|
|
22
|
+
{variant === 'plus-minus' ? (
|
|
23
|
+
<svg
|
|
24
|
+
width="16"
|
|
25
|
+
height="16"
|
|
26
|
+
viewBox="0 0 16 16"
|
|
27
|
+
fill="none"
|
|
28
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
29
|
+
>
|
|
30
|
+
{ }
|
|
31
|
+
<path
|
|
32
|
+
d="M4 8H12"
|
|
33
|
+
stroke="currentColor"
|
|
34
|
+
strokeWidth="2"
|
|
35
|
+
strokeLinecap="round"
|
|
36
|
+
strokeLinejoin="round"
|
|
37
|
+
/>
|
|
38
|
+
{ }
|
|
39
|
+
<path
|
|
40
|
+
d="M8 4V12"
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
strokeWidth="2"
|
|
43
|
+
strokeLinecap="round"
|
|
44
|
+
strokeLinejoin="round"
|
|
45
|
+
style={{
|
|
46
|
+
opacity: isExpanded ? 0 : 1,
|
|
47
|
+
transition: 'opacity 0.2s ease',
|
|
48
|
+
transformOrigin: 'center'
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
</svg>
|
|
52
|
+
) : (
|
|
53
|
+
<svg
|
|
54
|
+
width="16"
|
|
55
|
+
height="16"
|
|
56
|
+
viewBox="0 0 16 16"
|
|
57
|
+
fill="none"
|
|
58
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
59
|
+
style={{
|
|
60
|
+
transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)',
|
|
61
|
+
transition: 'transform 0.2s ease'
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<path
|
|
65
|
+
d="M6 4L10 8L6 12"
|
|
66
|
+
stroke="currentColor"
|
|
67
|
+
strokeWidth="2"
|
|
68
|
+
strokeLinecap="round"
|
|
69
|
+
strokeLinejoin="round"
|
|
70
|
+
/>
|
|
71
|
+
</svg>
|
|
72
|
+
)}
|
|
73
|
+
</button>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
.ogx-input-wrapper {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
position: relative;
|
|
5
|
+
border: var(--ogx-border-width-thin) solid var(--ogx-border-color);
|
|
6
|
+
border-radius: var(--ogx-border-radius-md);
|
|
7
|
+
background: var(--ogx-color-white);
|
|
8
|
+
transition: all var(--ogx-transition-duration-fast) var(--ogx-transition-easing);
|
|
9
|
+
}
|
|
10
|
+
.ogx-input-wrapper--full-width {
|
|
11
|
+
width: 100%;
|
|
12
|
+
}
|
|
13
|
+
.ogx-input {
|
|
14
|
+
flex: 1;
|
|
15
|
+
padding: var(--ogx-spacing-sm) var(--ogx-spacing-md);
|
|
16
|
+
font-family: var(--ogx-font-family);
|
|
17
|
+
font-size: var(--ogx-font-size-md);
|
|
18
|
+
line-height: var(--ogx-line-height-normal);
|
|
19
|
+
color: var(--ogx-color-gray-900);
|
|
20
|
+
background: transparent;
|
|
21
|
+
border: none;
|
|
22
|
+
outline: none;
|
|
23
|
+
}
|
|
24
|
+
.ogx-input::placeholder {
|
|
25
|
+
color: var(--ogx-color-gray-400);
|
|
26
|
+
}
|
|
27
|
+
.ogx-input__adornment {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
color: var(--ogx-color-gray-600);
|
|
31
|
+
}
|
|
32
|
+
.ogx-input__adornment--start {
|
|
33
|
+
padding-left: var(--ogx-spacing-md);
|
|
34
|
+
}
|
|
35
|
+
.ogx-input__adornment--end {
|
|
36
|
+
padding-right: var(--ogx-spacing-md);
|
|
37
|
+
}
|
|
38
|
+
.ogx-input-wrapper:hover:not(.ogx-input-wrapper--disabled) {
|
|
39
|
+
border-color: var(--ogx-border-color-hover);
|
|
40
|
+
}
|
|
41
|
+
.ogx-input-wrapper:focus-within:not(.ogx-input-wrapper--disabled) {
|
|
42
|
+
border-color: var(--ogx-color-primary);
|
|
43
|
+
box-shadow: 0 0 0 1px var(--ogx-color-primary);
|
|
44
|
+
}
|
|
45
|
+
.ogx-input-wrapper--error {
|
|
46
|
+
border-color: var(--ogx-color-error);
|
|
47
|
+
}
|
|
48
|
+
.ogx-input-wrapper--error:focus-within {
|
|
49
|
+
box-shadow: 0 0 0 1px var(--ogx-color-error);
|
|
50
|
+
}
|
|
51
|
+
.ogx-input-wrapper--disabled {
|
|
52
|
+
background: var(--ogx-color-gray-100);
|
|
53
|
+
border-color: var(--ogx-color-gray-200);
|
|
54
|
+
cursor: not-allowed;
|
|
55
|
+
opacity: 0.6;
|
|
56
|
+
}
|
|
57
|
+
.ogx-input-wrapper--disabled .ogx-input {
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
5
|
+
fullWidth?: boolean;
|
|
6
|
+
error?: boolean;
|
|
7
|
+
startAdornment?: React.ReactNode;
|
|
8
|
+
endAdornment?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const Input: React.FC<InputProps> = ({
|
|
12
|
+
fullWidth = false,
|
|
13
|
+
error = false,
|
|
14
|
+
startAdornment,
|
|
15
|
+
endAdornment,
|
|
16
|
+
className = '',
|
|
17
|
+
...props
|
|
18
|
+
}) => {
|
|
19
|
+
const wrapperClassNames = [
|
|
20
|
+
'ogx-input-wrapper',
|
|
21
|
+
fullWidth && 'ogx-input-wrapper--full-width',
|
|
22
|
+
error && 'ogx-input-wrapper--error',
|
|
23
|
+
props.disabled && 'ogx-input-wrapper--disabled',
|
|
24
|
+
className
|
|
25
|
+
].filter(Boolean).join(' ');
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div className={wrapperClassNames}>
|
|
29
|
+
{startAdornment && (
|
|
30
|
+
<div className="ogx-input__adornment ogx-input__adornment--start">
|
|
31
|
+
{startAdornment}
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
<input
|
|
35
|
+
className="ogx-input"
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
{endAdornment && (
|
|
39
|
+
<div className="ogx-input__adornment ogx-input__adornment--end">
|
|
40
|
+
{endAdornment}
|
|
41
|
+
</div>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
export { Button } from './Button';
|
|
3
|
+
export type { ButtonProps } from './Button';
|
|
4
|
+
|
|
5
|
+
export { Input } from './Input';
|
|
6
|
+
export type { InputProps } from './Input';
|
|
7
|
+
|
|
8
|
+
export { Checkbox } from './Checkbox';
|
|
9
|
+
export type { CheckboxProps } from './Checkbox';
|
|
10
|
+
|
|
11
|
+
export { ExpandIcon } from './ExpandIcon';
|
|
12
|
+
export type { ExpandIconProps } from './ExpandIcon';
|
|
13
|
+
|
|
14
|
+
export { DragHandleIcon } from './DragHandleIcon';
|
|
15
|
+
export type { DragHandleIconProps } from './DragHandleIcon';
|