@team-monolith/cds 0.1.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 (165) hide show
  1. package/README.md +46 -0
  2. package/dist/CodleDesignSystemProvider.d.ts +5 -0
  3. package/dist/CodleDesignSystemProvider.js +96 -0
  4. package/dist/components/AlertDialog/AlertDialog.d.ts +14 -0
  5. package/dist/components/AlertDialog/AlertDialog.js +45 -0
  6. package/dist/components/AlertDialog/AlertDialogActions.d.ts +8 -0
  7. package/dist/components/AlertDialog/AlertDialogActions.js +35 -0
  8. package/dist/components/AlertDialog/AlertDialogContent.d.ts +8 -0
  9. package/dist/components/AlertDialog/AlertDialogContent.js +36 -0
  10. package/dist/components/AlertDialog/AlertDialogTitle.d.ts +13 -0
  11. package/dist/components/AlertDialog/AlertDialogTitle.js +38 -0
  12. package/dist/components/AlertDialog/index.d.ts +4 -0
  13. package/dist/components/AlertDialog/index.js +4 -0
  14. package/dist/components/Banner.d.ts +29 -0
  15. package/dist/components/Banner.js +65 -0
  16. package/dist/components/Button.d.ts +26 -0
  17. package/dist/components/Button.js +72 -0
  18. package/dist/components/CheckboxInput.d.ts +27 -0
  19. package/dist/components/CheckboxInput.js +77 -0
  20. package/dist/components/Input.d.ts +17 -0
  21. package/dist/components/Input.js +72 -0
  22. package/dist/components/InputBase.d.ts +42 -0
  23. package/dist/components/InputBase.js +52 -0
  24. package/dist/components/Pagination.d.ts +27 -0
  25. package/dist/components/Pagination.js +32 -0
  26. package/dist/components/PinInput.d.ts +36 -0
  27. package/dist/components/PinInput.js +154 -0
  28. package/dist/components/RadioInput.d.ts +23 -0
  29. package/dist/components/RadioInput.js +78 -0
  30. package/dist/components/SquareButton.d.ts +26 -0
  31. package/dist/components/SquareButton.js +80 -0
  32. package/dist/components/Switch.d.ts +19 -0
  33. package/dist/components/Switch.js +59 -0
  34. package/dist/components/Tag.d.ts +21 -0
  35. package/dist/components/Tag.js +61 -0
  36. package/dist/components/Tooltip.d.ts +26 -0
  37. package/dist/components/Tooltip.js +50 -0
  38. package/dist/foundation/color.d.ts +75 -0
  39. package/dist/foundation/color.js +75 -0
  40. package/dist/foundation/shadows.d.ts +9 -0
  41. package/dist/foundation/shadows.js +10 -0
  42. package/dist/icons/arrows.d.ts +16 -0
  43. package/dist/icons/arrows.js +17 -0
  44. package/dist/icons/brand.d.ts +4 -0
  45. package/dist/icons/brand.js +13 -0
  46. package/dist/icons/map.d.ts +4 -0
  47. package/dist/icons/map.js +13 -0
  48. package/dist/icons/system.d.ts +25 -0
  49. package/dist/icons/system.js +20 -0
  50. package/dist/index.d.ts +2 -0
  51. package/dist/index.js +2 -0
  52. package/dist/patterns/Dropdown/Dropdown.d.ts +27 -0
  53. package/dist/patterns/Dropdown/Dropdown.js +41 -0
  54. package/dist/patterns/Dropdown/DropdownItem.d.ts +42 -0
  55. package/dist/patterns/Dropdown/DropdownItem.js +89 -0
  56. package/dist/patterns/Dropdown/DropdownMenu.d.ts +30 -0
  57. package/dist/patterns/Dropdown/DropdownMenu.js +85 -0
  58. package/dist/patterns/Dropdown/index.d.ts +2 -0
  59. package/dist/patterns/Dropdown/index.js +2 -0
  60. package/dist/patterns/EmptyState/EmptyState.d.ts +16 -0
  61. package/dist/patterns/EmptyState/EmptyState.js +36 -0
  62. package/dist/patterns/EmptyState/index.d.ts +2 -0
  63. package/dist/patterns/EmptyState/index.js +2 -0
  64. package/dist/patterns/Grid/EnhancedTableCell.d.ts +9 -0
  65. package/dist/patterns/Grid/EnhancedTableCell.js +122 -0
  66. package/dist/patterns/Grid/Grid.d.ts +51 -0
  67. package/dist/patterns/Grid/Grid.js +140 -0
  68. package/dist/patterns/Grid/index.d.ts +3 -0
  69. package/dist/patterns/Grid/index.js +2 -0
  70. package/dist/patterns/SegmentedControl/SegmentedControlButton.d.ts +8 -0
  71. package/dist/patterns/SegmentedControl/SegmentedControlButton.js +41 -0
  72. package/dist/patterns/SegmentedControl/SegmentedControlGroup.d.ts +26 -0
  73. package/dist/patterns/SegmentedControl/SegmentedControlGroup.js +50 -0
  74. package/dist/patterns/SegmentedControl/SegmentedControlGroupPropsContext.d.ts +5 -0
  75. package/dist/patterns/SegmentedControl/SegmentedControlGroupPropsContext.js +5 -0
  76. package/dist/patterns/SegmentedControl/SegmentedControlSquareButton.d.ts +8 -0
  77. package/dist/patterns/SegmentedControl/SegmentedControlSquareButton.js +45 -0
  78. package/dist/patterns/SegmentedControl/index.d.ts +3 -0
  79. package/dist/patterns/SegmentedControl/index.js +3 -0
  80. package/dist/patterns/Table/Table.d.ts +16 -0
  81. package/dist/patterns/Table/Table.js +33 -0
  82. package/dist/patterns/Table/TableBody.d.ts +8 -0
  83. package/dist/patterns/Table/TableBody.js +26 -0
  84. package/dist/patterns/Table/TableCell.d.ts +15 -0
  85. package/dist/patterns/Table/TableCell.js +78 -0
  86. package/dist/patterns/Table/TableHead.d.ts +8 -0
  87. package/dist/patterns/Table/TableHead.js +26 -0
  88. package/dist/patterns/Table/TableRow.d.ts +12 -0
  89. package/dist/patterns/Table/TableRow.js +29 -0
  90. package/dist/patterns/Table/TableSizeContext.d.ts +7 -0
  91. package/dist/patterns/Table/TableSizeContext.js +3 -0
  92. package/dist/patterns/Table/TableVariantContext.d.ts +6 -0
  93. package/dist/patterns/Table/TableVariantContext.js +3 -0
  94. package/dist/patterns/Table/index.d.ts +7 -0
  95. package/dist/patterns/Table/index.js +6 -0
  96. package/dist/utils/hover.d.ts +3 -0
  97. package/dist/utils/hover.js +14 -0
  98. package/dist/utils/reset.d.ts +2 -0
  99. package/dist/utils/reset.js +8 -0
  100. package/dist/utils/zIndex.d.ts +3 -0
  101. package/dist/utils/zIndex.js +3 -0
  102. package/package.json +52 -0
  103. package/public/favicon.ico +0 -0
  104. package/public/index.html +43 -0
  105. package/public/logo192.png +0 -0
  106. package/public/logo512.png +0 -0
  107. package/public/manifest.json +25 -0
  108. package/public/robots.txt +3 -0
  109. package/src/App.tsx +7 -0
  110. package/src/cds/CodleDesignSystemProvider.tsx +93 -0
  111. package/src/cds/README.md +23 -0
  112. package/src/cds/components/AlertDialog/AlertDialog.tsx +101 -0
  113. package/src/cds/components/AlertDialog/AlertDialogActions.tsx +34 -0
  114. package/src/cds/components/AlertDialog/AlertDialogContent.tsx +38 -0
  115. package/src/cds/components/AlertDialog/AlertDialogTitle.tsx +63 -0
  116. package/src/cds/components/AlertDialog/index.tsx +4 -0
  117. package/src/cds/components/Banner.tsx +176 -0
  118. package/src/cds/components/Button.tsx +239 -0
  119. package/src/cds/components/CheckboxInput.tsx +270 -0
  120. package/src/cds/components/Input.tsx +166 -0
  121. package/src/cds/components/InputBase.tsx +226 -0
  122. package/src/cds/components/Pagination.tsx +99 -0
  123. package/src/cds/components/PinInput.tsx +322 -0
  124. package/src/cds/components/RadioInput.tsx +226 -0
  125. package/src/cds/components/SquareButton.tsx +229 -0
  126. package/src/cds/components/Switch.tsx +129 -0
  127. package/src/cds/components/Tag.tsx +155 -0
  128. package/src/cds/components/Tooltip.tsx +104 -0
  129. package/src/cds/emotion.d.ts +70 -0
  130. package/src/cds/foundation/color.ts +83 -0
  131. package/src/cds/foundation/shadows.ts +17 -0
  132. package/src/cds/icons/arrows.tsx +61 -0
  133. package/src/cds/icons/brand.tsx +13 -0
  134. package/src/cds/icons/map.tsx +14 -0
  135. package/src/cds/icons/system.tsx +113 -0
  136. package/src/cds/index.ts +3 -0
  137. package/src/cds/patterns/Dropdown/Dropdown.tsx +111 -0
  138. package/src/cds/patterns/Dropdown/DropdownItem.tsx +203 -0
  139. package/src/cds/patterns/Dropdown/DropdownMenu.tsx +176 -0
  140. package/src/cds/patterns/Dropdown/index.tsx +2 -0
  141. package/src/cds/patterns/EmptyState/EmptyState.tsx +91 -0
  142. package/src/cds/patterns/EmptyState/empty-state-icon.svg +36 -0
  143. package/src/cds/patterns/EmptyState/index.tsx +2 -0
  144. package/src/cds/patterns/Grid/EnhancedTableCell.tsx +180 -0
  145. package/src/cds/patterns/Grid/Grid.tsx +360 -0
  146. package/src/cds/patterns/Grid/index.tsx +4 -0
  147. package/src/cds/patterns/SegmentedControl/SegmentedControlButton.tsx +41 -0
  148. package/src/cds/patterns/SegmentedControl/SegmentedControlGroup.tsx +81 -0
  149. package/src/cds/patterns/SegmentedControl/SegmentedControlGroupPropsContext.tsx +9 -0
  150. package/src/cds/patterns/SegmentedControl/SegmentedControlSquareButton.tsx +51 -0
  151. package/src/cds/patterns/SegmentedControl/index.ts +3 -0
  152. package/src/cds/patterns/Table/Table.tsx +56 -0
  153. package/src/cds/patterns/Table/TableBody.tsx +30 -0
  154. package/src/cds/patterns/Table/TableCell.tsx +242 -0
  155. package/src/cds/patterns/Table/TableHead.tsx +30 -0
  156. package/src/cds/patterns/Table/TableRow.tsx +54 -0
  157. package/src/cds/patterns/Table/TableSizeContext.tsx +10 -0
  158. package/src/cds/patterns/Table/TableVariantContext.tsx +9 -0
  159. package/src/cds/patterns/Table/index.tsx +15 -0
  160. package/src/cds/utils/hover.tsx +24 -0
  161. package/src/cds/utils/reset.tsx +19 -0
  162. package/src/cds/utils/zIndex.tsx +3 -0
  163. package/src/index.tsx +10 -0
  164. package/src/react-app-env.d.ts +1 -0
  165. package/tsconfig.json +22 -0
@@ -0,0 +1,360 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import {
3
+ Cell,
4
+ ColumnDef,
5
+ ColumnFiltersState,
6
+ ColumnResizeMode,
7
+ Row,
8
+ RowData,
9
+ RowSelectionState,
10
+ SortingState,
11
+ Table as TableType,
12
+ flexRender,
13
+ getCoreRowModel,
14
+ getFacetedRowModel,
15
+ getFacetedUniqueValues,
16
+ getFilteredRowModel,
17
+ getPaginationRowModel,
18
+ getSortedRowModel,
19
+ useReactTable,
20
+ FilterFn,
21
+ PaginationState,
22
+ } from "@tanstack/react-table";
23
+ import React, { RefObject, useImperativeHandle, useRef, useState } from "react";
24
+ import styled from "@emotion/styled";
25
+ import { css } from "@emotion/react";
26
+ import Pagination from "../../components/Pagination";
27
+ import CheckboxInput from "../../components/CheckboxInput";
28
+ import { DropdownItemProps } from "../Dropdown/DropdownItem";
29
+ import Button from "../../components/Button";
30
+ import DropdownMenu from "../Dropdown/DropdownMenu";
31
+ import { ArrowDropDownFillIcon } from "../../icons/arrows";
32
+ import {
33
+ Table,
34
+ TableBody,
35
+ TableCell,
36
+ TableHead,
37
+ TableRow,
38
+ TableSize,
39
+ } from "../Table";
40
+ import EnhancedTableCell from "./EnhancedTableCell";
41
+
42
+ // TanStack Table의 기본 Filter 함수들은 단일 Filter 값만 지원하도록 되어있습니다.
43
+ // CDS에서는 여러개 필터값을 선택할 수 있으므로,
44
+ // FilterValue를 Set 형식으로 지정하고, 이 형식에 맞는 Filter 함수를 정의하여
45
+ // 각 columnDef의 인자로 전달하여 적용합니다.
46
+ const MultiFilterFn: FilterFn<any> = (
47
+ row,
48
+ columnId: string,
49
+ filterValues: Set<any>
50
+ ) => {
51
+ return filterValues.has(row.getValue<string | null>(columnId));
52
+ };
53
+
54
+ // onCellClicked 함수의 인자로 전달되는 값
55
+ export interface CellClickedEvent<TData> {
56
+ cell: Cell<TData, any>;
57
+ table: TableType<TData>;
58
+ }
59
+
60
+ // selectedRowMenuProps의 onClick 함수의 인자로 전달되는 값
61
+ export interface SelectedRowMenuOnClickArgs<TData> {
62
+ rows: Row<TData>[];
63
+ table: TableType<TData>;
64
+ setDropdownOpen: React.Dispatch<React.SetStateAction<boolean>>;
65
+ }
66
+
67
+ export interface GridApi<TData> {
68
+ table: TableType<TData>;
69
+ }
70
+
71
+ export interface GridProps<TData> {
72
+ className?: string;
73
+ component?: React.ElementType;
74
+
75
+ /** Grid API를 담는 Ref 객체 */
76
+ gridApiRef: RefObject<GridApi<TData>>;
77
+ /** Table Cell의 크기 옵션*/
78
+ size: TableSize;
79
+ /** Table의 fullWidth 여부
80
+ * @default true */
81
+ fullWidth?: boolean;
82
+ /** 행 Data */
83
+ rowData: TData[];
84
+ /** 열 정의 객체 */
85
+ columns: ColumnDef<TData, any>[];
86
+ /** Table의 열 크기를 resize 할 수 있는지 여부*/
87
+ resizable?: boolean;
88
+ /** 한 페이지 당 보여질 row의 갯수. 입력하지 않으면 페이지네이션이 비활성화됩니다. */
89
+ paginationPageSize?: number;
90
+ /** Cell을 클릭했을 때 호출되는 콜백 */
91
+ onCellClicked?: (event: CellClickedEvent<TData>) => void;
92
+ /** 행 선택 기능 활성화 여부 */
93
+ enableRowSelection?: boolean;
94
+ /** 행 선택 기능에서 '선택한 항목을' DropdownMenu 관련 속성 */
95
+ selectedRowMenuProps?: {
96
+ items: (Omit<DropdownItemProps, "onClick"> & {
97
+ onClick: (args: SelectedRowMenuOnClickArgs<TData>) => void;
98
+ })[];
99
+ };
100
+ }
101
+
102
+ /**
103
+ * CDS Table과 TanStack Table을 이용하여
104
+ * data-processing, state-management 등의 로직이 들어있는 컴포넌트입니다.
105
+ */
106
+ export default function Grid<TData extends RowData>(props: GridProps<TData>) {
107
+ const {
108
+ className,
109
+ component: Component = "div",
110
+ gridApiRef,
111
+ size,
112
+ fullWidth = true,
113
+ rowData,
114
+ columns,
115
+ onCellClicked,
116
+ resizable,
117
+ selectedRowMenuProps,
118
+ paginationPageSize,
119
+ enableRowSelection,
120
+ } = props;
121
+ const [sorting, setSorting] = useState<SortingState>([]);
122
+ const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
123
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
124
+ const [{ pageIndex }, setPagination] = useState<PaginationState>({
125
+ pageIndex: 0,
126
+ pageSize: 0,
127
+ });
128
+ const [selectedRowMenuOpen, setSelectedRowMenuOpen] = useState(false);
129
+
130
+ // resize가 활성화 되었을 때만 전달되는 Table Option
131
+ const resizeOption = resizable
132
+ ? {
133
+ enableColumnResizing: true,
134
+ columnResizeMode: "onChange" as ColumnResizeMode,
135
+ }
136
+ : { enableColumnResizing: false };
137
+
138
+ // rowSelection이 활성화 되었을 때만 전달되는 Table Option
139
+ const rowSelectionOption = enableRowSelection
140
+ ? {
141
+ enableRowSelection: true,
142
+ onRowSelectionChange: setRowSelection,
143
+ }
144
+ : {};
145
+ // rowSelection이 활성화 되었을 때, 다음 column을 가장 처음 열에 추가합니다.
146
+ const selectColumn: ColumnDef<TData> = {
147
+ id: "grid-selectable-column",
148
+ header: ({ table }) => (
149
+ <CheckboxInput
150
+ checked={table.getIsAllRowsSelected()}
151
+ partial={table.getIsSomeRowsSelected()}
152
+ onChange={table.getToggleAllRowsSelectedHandler()}
153
+ />
154
+ ),
155
+ cell: ({ row }) => (
156
+ <CheckboxInput
157
+ checked={row.getIsSelected()}
158
+ disabled={!row.getCanSelect()}
159
+ partial={row.getIsSomeSelected()}
160
+ onChange={row.getToggleSelectedHandler()}
161
+ />
162
+ ),
163
+ enableResizing: false,
164
+ enableColumnFilter: false,
165
+ enableSorting: false,
166
+ size: 0,
167
+ };
168
+
169
+ // pagination이 활성화 되었을 때만 전달되는 Table Option
170
+ const paginationOption = paginationPageSize
171
+ ? {
172
+ onPaginationChange: setPagination,
173
+ getPaginationRowModel: getPaginationRowModel(),
174
+ }
175
+ : {};
176
+ const pagination: PaginationState = {
177
+ pageIndex,
178
+ pageSize: paginationPageSize ?? 0,
179
+ };
180
+
181
+ // 여러 값으로 된 필터를 선택할 수 있도록 filterFn을 교체합니다.
182
+ const columnWithFilterFn: ColumnDef<TData, any>[] = columns.map((colDef) => ({
183
+ ...colDef,
184
+ filterFn: MultiFilterFn,
185
+ }));
186
+
187
+ const table = useReactTable<TData>({
188
+ data: rowData,
189
+ columns: enableRowSelection
190
+ ? [selectColumn, ...columnWithFilterFn]
191
+ : columnWithFilterFn,
192
+ state: {
193
+ columnFilters,
194
+ sorting,
195
+ rowSelection,
196
+ pagination,
197
+ },
198
+ ...resizeOption,
199
+ ...rowSelectionOption,
200
+ ...paginationOption,
201
+ getCoreRowModel: getCoreRowModel(),
202
+ onSortingChange: setSorting,
203
+ getSortedRowModel: getSortedRowModel(),
204
+ onColumnFiltersChange: setColumnFilters,
205
+ getFilteredRowModel: getFilteredRowModel(),
206
+ getFacetedRowModel: getFacetedRowModel(),
207
+ getFacetedUniqueValues: getFacetedUniqueValues(),
208
+ });
209
+
210
+ useImperativeHandle(gridApiRef, () => ({
211
+ table,
212
+ }));
213
+
214
+ const enablePagination = Boolean(paginationPageSize);
215
+
216
+ const menuRef = useRef<HTMLButtonElement | null>(null);
217
+ // selectedRowMenuProps의 onClick 인자에 rows, table, setDropdownOpen을 전달하여
218
+ // 콜백 내부에서 접근 가능하게 합니다.
219
+ const itemProps =
220
+ selectedRowMenuProps?.items.map((itemProp) => {
221
+ return {
222
+ ...itemProp,
223
+ onClick: () => {
224
+ itemProp.onClick({
225
+ rows: table.getSelectedRowModel().flatRows,
226
+ table,
227
+ setDropdownOpen: setSelectedRowMenuOpen,
228
+ });
229
+ },
230
+ };
231
+ }) ?? [];
232
+
233
+ return (
234
+ <Component
235
+ className={className}
236
+ css={[
237
+ css`
238
+ display: inline-flex;
239
+ flex-direction: column;
240
+ `,
241
+ fullWidth &&
242
+ css`
243
+ width: 100%;
244
+ `,
245
+ ]}
246
+ >
247
+ <div
248
+ css={css`
249
+ // Table을 div으로 감싸 overflow 속성을 추가하여 스크롤 가능하게 합니다.
250
+ // Table 자체에 css를 적용하면 display: table 속성으로 인해 적용되지 않습니다.
251
+ overflow: auto;
252
+ `}
253
+ >
254
+ <Table {...{ size, fullWidth }}>
255
+ <TableHead>
256
+ {table.getHeaderGroups().map((headerGroup) => (
257
+ <TableRow key={headerGroup.id}>
258
+ {headerGroup.headers.map((header) => (
259
+ <EnhancedTableCell
260
+ table={table}
261
+ header={header}
262
+ key={header.id}
263
+ />
264
+ ))}
265
+ </TableRow>
266
+ ))}
267
+ </TableHead>
268
+ <TableBody>
269
+ {table.getRowModel().rows.length === 0 && (
270
+ <TableRow disableHover>
271
+ <TableCell
272
+ colSpan={table.getAllColumns().length}
273
+ css={css`
274
+ text-align: center;
275
+ `}
276
+ >
277
+ 데이터가 존재하지 않습니다.
278
+ </TableCell>
279
+ </TableRow>
280
+ )}
281
+ {table.getRowModel().rows.map((row) => (
282
+ <TableRow key={row.id} isSelected={row.getIsSelected()}>
283
+ {row.getVisibleCells().map((cell) => (
284
+ <TableCell
285
+ key={cell.id}
286
+ onClick={() => onCellClicked?.({ cell, table })}
287
+ >
288
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
289
+ </TableCell>
290
+ ))}
291
+ </TableRow>
292
+ ))}
293
+ </TableBody>
294
+ </Table>
295
+ </div>
296
+ {(enableRowSelection || enablePagination) && (
297
+ <TableFooter
298
+ enableRowSelection={enableRowSelection ?? false}
299
+ enablePagination={enablePagination}
300
+ >
301
+ {enableRowSelection && (
302
+ <>
303
+ <Button
304
+ color="secondary"
305
+ size="small"
306
+ label="선택한 항목을"
307
+ ref={menuRef}
308
+ endIcon={<ArrowDropDownFillIcon />}
309
+ disabled={
310
+ !(
311
+ table.getIsAllRowsSelected() ||
312
+ table.getIsSomeRowsSelected()
313
+ )
314
+ }
315
+ onClick={() => setSelectedRowMenuOpen(true)}
316
+ />
317
+ <DropdownMenu
318
+ itemsProps={itemProps}
319
+ open={selectedRowMenuOpen}
320
+ anchorEl={menuRef.current}
321
+ onClose={() => setSelectedRowMenuOpen(false)}
322
+ />
323
+ </>
324
+ )}
325
+ {enablePagination && (
326
+ <Pagination
327
+ page={table.getState().pagination.pageIndex + 1}
328
+ count={table.getPageCount()}
329
+ onChange={(event, page) => {
330
+ table.setPageIndex(page - 1);
331
+ }}
332
+ />
333
+ )}
334
+ </TableFooter>
335
+ )}
336
+ </Component>
337
+ );
338
+ }
339
+
340
+ const TableFooter = styled.div<{
341
+ enableRowSelection: boolean;
342
+ enablePagination: boolean;
343
+ }>`
344
+ display: flex;
345
+ align-items: center;
346
+
347
+ ${({ enableRowSelection, enablePagination }) =>
348
+ !enablePagination
349
+ ? css`
350
+ justify-content: flex-start;
351
+ `
352
+ : enableRowSelection
353
+ ? css`
354
+ justify-content: space-between;
355
+ `
356
+ : css`
357
+ justify-content: center;
358
+ `}
359
+ margin: 16px 12px;
360
+ `;
@@ -0,0 +1,4 @@
1
+ import Grid from "./Grid";
2
+
3
+ export type { GridProps, GridApi, CellClickedEvent } from "./Grid";
4
+ export default Grid;
@@ -0,0 +1,41 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import styled from "@emotion/styled";
3
+ import { useContext } from "react";
4
+ import Button, { ButtonProps } from "../../components/Button";
5
+ import shadows from "../../foundation/shadows";
6
+ import { SegmentedControlGroupPropsContext } from "./SegmentedControlGroupPropsContext";
7
+
8
+ export interface SegmentedControlButtonProps extends Omit<ButtonProps, "color" | "size"> {
9
+ value: string;
10
+ }
11
+
12
+ /**
13
+ * [피그마](https://www.figma.com/file/PnQp3tPxiCjgsPZfLUaUL1/Codle-PD-Kit---Patterns?node-id=181%3A89883)
14
+ */
15
+ export function SegmentedControlButton(props: SegmentedControlButtonProps) {
16
+ const context = useContext(SegmentedControlGroupPropsContext);
17
+
18
+ const isActive = context.multiSelect ? context.value.includes(props.value) : context.value === props.value;
19
+
20
+ return (
21
+ <StyledButton
22
+ {...props}
23
+ isActive={isActive}
24
+ color={isActive ? "primary" : "textNeutral"}
25
+ size={context.size}
26
+ onClick={() => {
27
+ context.onClick?.(props.value);
28
+ props.onClick?.();
29
+ }}
30
+ />
31
+ );
32
+ }
33
+
34
+ const StyledButton = styled(Button, {
35
+ shouldForwardProp: (prop) => prop !== "isActive",
36
+ })<{ isActive: boolean }>`
37
+ display: flex;
38
+ justify-content: center;
39
+ flex-grow: 1;
40
+ ${({ isActive }) => isActive && `box-shadow: ${shadows.shadow04};`}
41
+ `;
@@ -0,0 +1,81 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css, useTheme } from "@emotion/react";
3
+ import { ButtonSize } from "../../components/Button";
4
+ import { SquareButtonSize } from "../../components/SquareButton";
5
+ import { SegmentedControlGroupPropsContext } from "./SegmentedControlGroupPropsContext";
6
+
7
+ export type SegmentedControlGroupProps = {
8
+ className?: string;
9
+ component?: React.ElementType;
10
+ children?: React.ReactNode;
11
+
12
+ /** 컴포넌트 크기 */
13
+ size: ButtonSize | SquareButtonSize;
14
+
15
+ /** 전체 너비 유무 */
16
+ fullWidth?: boolean;
17
+ } & (
18
+ | {
19
+ /** 중복 선택 가능 유무 */
20
+ multiSelect?: false;
21
+ /** 선택된 값 */
22
+ value: string | undefined;
23
+ onChange?: (newValue: string) => void;
24
+ }
25
+ | {
26
+ multiSelect: true;
27
+ value: string[];
28
+ onChange?: (newValue: string[]) => void;
29
+ }
30
+ );
31
+
32
+ /**
33
+ * [피그마](https://www.figma.com/file/PnQp3tPxiCjgsPZfLUaUL1/Codle-PD-Kit---Patterns?node-id=181%3A89883)
34
+ */
35
+ export function SegmentedControlGroup(props: SegmentedControlGroupProps) {
36
+ const {
37
+ component: Component = "div",
38
+ className,
39
+ children,
40
+ fullWidth,
41
+ multiSelect,
42
+ } = props;
43
+
44
+ const theme = useTheme();
45
+
46
+ return (
47
+ <Component
48
+ className={className}
49
+ css={css`
50
+ display: flex;
51
+ gap: 4px;
52
+
53
+ width: ${fullWidth ? "100%" : "fit-content"};
54
+ background-color: ${theme.color.background.neutralAlt};
55
+ border-radius: 8px;
56
+ border: 1px solid ${theme.color.background.neutralAltActive};
57
+ `}
58
+ >
59
+ <SegmentedControlGroupPropsContext.Provider
60
+ value={{
61
+ ...props,
62
+ onClick: (newValue: string) => {
63
+ if (multiSelect) {
64
+ if (props.value.includes(newValue)) {
65
+ props.onChange?.(
66
+ props.value.filter((value) => value !== newValue)
67
+ );
68
+ } else {
69
+ props.onChange?.([...props.value, newValue]);
70
+ }
71
+ } else {
72
+ props.onChange?.(newValue);
73
+ }
74
+ },
75
+ }}
76
+ >
77
+ {children}
78
+ </SegmentedControlGroupPropsContext.Provider>
79
+ </Component>
80
+ );
81
+ }
@@ -0,0 +1,9 @@
1
+ import { createContext } from "react";
2
+ import { SegmentedControlGroupProps } from "./SegmentedControlGroup";
3
+
4
+ export const SegmentedControlGroupPropsContext = createContext<SegmentedControlGroupProps & {
5
+ onClick?: (newValue: string) => void;
6
+ }>({
7
+ value: undefined,
8
+ size: "medium",
9
+ });
@@ -0,0 +1,51 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import styled from "@emotion/styled";
3
+ import { useContext } from "react";
4
+ import SquareButton, { SquareButtonProps } from "../../components/SquareButton";
5
+ import shadows from "../../foundation/shadows";
6
+ import { SegmentedControlGroupPropsContext } from "./SegmentedControlGroupPropsContext";
7
+
8
+ export interface SegmentedControlSquareButtonProps
9
+ extends Omit<SquareButtonProps, "color" | "size"> {
10
+ value: string;
11
+ }
12
+
13
+ /**
14
+ * [피그마](https://www.figma.com/file/PnQp3tPxiCjgsPZfLUaUL1/Codle-PD-Kit---Patterns?node-id=181%3A89883)
15
+ */
16
+ export function SegmentedControlSquareButton(
17
+ props: SegmentedControlSquareButtonProps
18
+ ) {
19
+ const context = useContext(SegmentedControlGroupPropsContext);
20
+
21
+ const isActive = context.multiSelect
22
+ ? context.value.includes(props.value)
23
+ : context.value === props.value;
24
+
25
+ return (
26
+ <StyledSquareButton
27
+ {...props}
28
+ isActive={isActive}
29
+ color={isActive ? "primary" : "icon"}
30
+ size={context.size}
31
+ fullWidth={context.fullWidth}
32
+ onClick={() => {
33
+ if (context.onClick) {
34
+ context.onClick(props.value);
35
+ props.onClick?.();
36
+ }
37
+ }}
38
+ />
39
+ );
40
+ }
41
+
42
+ const StyledSquareButton = styled(SquareButton, {
43
+ shouldForwardProp: (prop) => prop !== "isActive",
44
+ })<{ isActive: boolean }>`
45
+ display: flex;
46
+ justify-content: center;
47
+ flex-grow: 1;
48
+ button {
49
+ ${({ isActive }) => isActive && `box-shadow: ${shadows.shadow04};`}
50
+ }
51
+ `;
@@ -0,0 +1,3 @@
1
+ export * from './SegmentedControlGroup';
2
+ export * from './SegmentedControlButton';
3
+ export * from './SegmentedControlSquareButton';
@@ -0,0 +1,56 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css, useTheme } from "@emotion/react";
3
+ import React from "react";
4
+ import { RESET_TABLE } from "../../utils/reset";
5
+ import TableSizeContext from "./TableSizeContext";
6
+
7
+ export type TableSize = "large" | "medium" | "small";
8
+ export interface TableProps {
9
+ className?: string;
10
+ component?: React.ElementType;
11
+
12
+ /** Table의 내용입니다. 일반적으로 `TableHead`와 `TableBody`로 구성됩니다. */
13
+ children?: React.ReactNode;
14
+
15
+ /** Table Row 사이즈 */
16
+ size: TableSize;
17
+
18
+ /** fullWidth 여부 */
19
+ fullWidth?: boolean;
20
+ }
21
+
22
+ /**
23
+ * [피그마](https://www.figma.com/file/PnQp3tPxiCjgsPZfLUaUL1/Codle-PD-Kit---Patterns?type=design&node-id=181-91732&t=07ngLzGHuU3xxg4S-0)
24
+ */
25
+ export default function Table(props: TableProps) {
26
+ const {
27
+ className,
28
+ component: Component = "table",
29
+ children,
30
+ size,
31
+ fullWidth,
32
+ } = props;
33
+ const theme = useTheme();
34
+ return (
35
+ <Component
36
+ className={className}
37
+ css={[
38
+ RESET_TABLE,
39
+ css`
40
+ border-collapse: separate;
41
+
42
+ background: ${theme.color.background.neutralBase};
43
+ border: 1px solid ${theme.color.background.neutralAlt};
44
+ color: ${theme.color.foreground.neutralBase};
45
+ border-radius: 4px;
46
+ `,
47
+ fullWidth &&
48
+ css`
49
+ width: 100%;
50
+ `,
51
+ ]}
52
+ >
53
+ <TableSizeContext.Provider value={{ size }}>{children}</TableSizeContext.Provider>
54
+ </Component>
55
+ );
56
+ }
@@ -0,0 +1,30 @@
1
+ /** @jsxImportSource @emotion/react */
2
+ import { css } from "@emotion/react";
3
+ import React from "react";
4
+ import TableVariantContext from "./TableVariantContext";
5
+
6
+ export interface TableBodyProps {
7
+ className?: string;
8
+ component?: React.ElementType;
9
+
10
+ /** Table의 내용입니다. 일반적으로 TableRow로 구성됩니다. */
11
+ children?: React.ReactNode;
12
+ }
13
+
14
+ export default function TableBody(props: TableBodyProps) {
15
+ const { className, component: Component = "tbody", children } = props;
16
+ return (
17
+ <Component
18
+ className={className}
19
+ css={[
20
+ css`
21
+ display: table-row-group;
22
+ `,
23
+ ]}
24
+ >
25
+ <TableVariantContext.Provider value={{ variant: "body" }}>
26
+ {children}
27
+ </TableVariantContext.Provider>
28
+ </Component>
29
+ );
30
+ }