@ttdk-design-system/library-react 0.0.0-stage → 1.0.1

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 (184) hide show
  1. package/AI_GUIDE.md +6518 -0
  2. package/README.md +106 -2
  3. package/llms.txt +6518 -0
  4. package/package.json +1099 -4
  5. package/src/core/index.ts +2 -0
  6. package/src/core/tailwind-preset.cjs +62 -0
  7. package/src/core/tailwind-preset.ts +85 -0
  8. package/src/core/theme/tokens.css +663 -0
  9. package/src/core/types.ts +836 -0
  10. package/src/index.ts +17 -0
  11. package/src/tailwind-preset.cjs +62 -0
  12. package/src/tailwind-preset.ts +85 -0
  13. package/src/types.ts +1 -0
  14. package/src/web/accordion/AI_GUIDE.md +149 -0
  15. package/src/web/accordion/accordion.css +1 -0
  16. package/src/web/accordion/accordion.tsx +430 -0
  17. package/src/web/accordion/index.ts +3 -0
  18. package/src/web/accordion/manifest.json +351 -0
  19. package/src/web/alert/AI_GUIDE.md +139 -0
  20. package/src/web/alert/alert.css +1 -0
  21. package/src/web/alert/alert.tsx +318 -0
  22. package/src/web/alert/index.ts +3 -0
  23. package/src/web/alert/manifest.json +240 -0
  24. package/src/web/avatar/AI_GUIDE.md +118 -0
  25. package/src/web/avatar/avatar.css +1 -0
  26. package/src/web/avatar/avatar.tsx +233 -0
  27. package/src/web/avatar/index.ts +3 -0
  28. package/src/web/avatar/manifest.json +195 -0
  29. package/src/web/badge/AI_GUIDE.md +94 -0
  30. package/src/web/badge/badge.css +1 -0
  31. package/src/web/badge/badge.tsx +140 -0
  32. package/src/web/badge/index.ts +2 -0
  33. package/src/web/badge/manifest.json +141 -0
  34. package/src/web/banner/AI_GUIDE.md +130 -0
  35. package/src/web/banner/banner.css +1 -0
  36. package/src/web/banner/banner.tsx +334 -0
  37. package/src/web/banner/index.ts +3 -0
  38. package/src/web/banner/manifest.json +240 -0
  39. package/src/web/breadcrumb/AI_GUIDE.md +120 -0
  40. package/src/web/breadcrumb/breadcrumb.css +1 -0
  41. package/src/web/breadcrumb/breadcrumb.tsx +306 -0
  42. package/src/web/breadcrumb/index.ts +3 -0
  43. package/src/web/breadcrumb/manifest.json +225 -0
  44. package/src/web/button/AI_GUIDE.md +121 -0
  45. package/src/web/button/button.css +1 -0
  46. package/src/web/button/button.tsx +287 -0
  47. package/src/web/button/index.ts +2 -0
  48. package/src/web/button/manifest.json +177 -0
  49. package/src/web/calendar/AI_GUIDE.md +151 -0
  50. package/src/web/calendar/calendar.css +1 -0
  51. package/src/web/calendar/calendar.tsx +1611 -0
  52. package/src/web/calendar/index.ts +3 -0
  53. package/src/web/calendar/manifest.json +470 -0
  54. package/src/web/card/AI_GUIDE.md +133 -0
  55. package/src/web/card/card.css +1 -0
  56. package/src/web/card/card.tsx +408 -0
  57. package/src/web/card/index.ts +4 -0
  58. package/src/web/card/manifest.json +357 -0
  59. package/src/web/checkbox/AI_GUIDE.md +146 -0
  60. package/src/web/checkbox/checkbox.css +1 -0
  61. package/src/web/checkbox/checkbox.tsx +307 -0
  62. package/src/web/checkbox/index.ts +2 -0
  63. package/src/web/checkbox/manifest.json +294 -0
  64. package/src/web/chip/AI_GUIDE.md +186 -0
  65. package/src/web/chip/chip.css +1 -0
  66. package/src/web/chip/chip.tsx +230 -0
  67. package/src/web/chip/index.ts +2 -0
  68. package/src/web/chip/manifest.json +186 -0
  69. package/src/web/dropdown/AI_GUIDE.md +167 -0
  70. package/src/web/dropdown/dropdown.css +1 -0
  71. package/src/web/dropdown/dropdown.tsx +1274 -0
  72. package/src/web/dropdown/index.ts +3 -0
  73. package/src/web/dropdown/manifest.json +576 -0
  74. package/src/web/flex/AI_GUIDE.md +113 -0
  75. package/src/web/flex/flex-item.tsx +97 -0
  76. package/src/web/flex/flex.css +1 -0
  77. package/src/web/flex/flex.tsx +108 -0
  78. package/src/web/flex/index.ts +5 -0
  79. package/src/web/flex/manifest.json +162 -0
  80. package/src/web/form/index.ts +7 -0
  81. package/src/web/grid/AI_GUIDE.md +112 -0
  82. package/src/web/grid/grid-item.tsx +112 -0
  83. package/src/web/grid/grid.css +1 -0
  84. package/src/web/grid/grid.tsx +99 -0
  85. package/src/web/grid/index.ts +5 -0
  86. package/src/web/grid/manifest.json +153 -0
  87. package/src/web/index.ts +86 -0
  88. package/src/web/input/AI_GUIDE.md +159 -0
  89. package/src/web/input/index.ts +3 -0
  90. package/src/web/input/input.css +1 -0
  91. package/src/web/input/input.tsx +537 -0
  92. package/src/web/input/manifest.json +465 -0
  93. package/src/web/input-number/AI_GUIDE.md +164 -0
  94. package/src/web/input-number/index.ts +3 -0
  95. package/src/web/input-number/input-number.css +1 -0
  96. package/src/web/input-number/input-number.tsx +1193 -0
  97. package/src/web/input-number/manifest.json +575 -0
  98. package/src/web/modal/AI_GUIDE.md +171 -0
  99. package/src/web/modal/index.ts +3 -0
  100. package/src/web/modal/manifest.json +375 -0
  101. package/src/web/modal/modal.css +1 -0
  102. package/src/web/modal/modal.tsx +571 -0
  103. package/src/web/pagination/AI_GUIDE.md +148 -0
  104. package/src/web/pagination/index.ts +21 -0
  105. package/src/web/pagination/manifest.json +432 -0
  106. package/src/web/pagination/pagination-content.tsx +45 -0
  107. package/src/web/pagination/pagination-ellipsis.tsx +54 -0
  108. package/src/web/pagination/pagination-first.tsx +155 -0
  109. package/src/web/pagination/pagination-item.tsx +45 -0
  110. package/src/web/pagination/pagination-last.tsx +155 -0
  111. package/src/web/pagination/pagination-link.tsx +121 -0
  112. package/src/web/pagination/pagination-next.tsx +158 -0
  113. package/src/web/pagination/pagination-previous.tsx +158 -0
  114. package/src/web/pagination/pagination.css +1 -0
  115. package/src/web/pagination/pagination.tsx +687 -0
  116. package/src/web/popover/AI_GUIDE.md +163 -0
  117. package/src/web/popover/index.ts +3 -0
  118. package/src/web/popover/manifest.json +396 -0
  119. package/src/web/popover/popover.css +1 -0
  120. package/src/web/popover/popover.tsx +702 -0
  121. package/src/web/radio/AI_GUIDE.md +155 -0
  122. package/src/web/radio/index.ts +2 -0
  123. package/src/web/radio/manifest.json +294 -0
  124. package/src/web/radio/radio.css +1 -0
  125. package/src/web/radio/radio.tsx +290 -0
  126. package/src/web/selectbox/AI_GUIDE.md +216 -0
  127. package/src/web/selectbox/index.ts +3 -0
  128. package/src/web/selectbox/manifest.json +477 -0
  129. package/src/web/selectbox/selectbox.css +1 -0
  130. package/src/web/selectbox/selectbox.tsx +1048 -0
  131. package/src/web/sonner/AI_GUIDE.md +98 -0
  132. package/src/web/sonner/index.ts +114 -0
  133. package/src/web/sonner/manifest.json +132 -0
  134. package/src/web/sonner/sonner.css +1 -0
  135. package/src/web/sonner/sonner.tsx +177 -0
  136. package/src/web/table/AI_GUIDE.md +145 -0
  137. package/src/web/table/index.ts +35 -0
  138. package/src/web/table/manifest.json +168 -0
  139. package/src/web/table/table-body.tsx +45 -0
  140. package/src/web/table/table-caption.tsx +45 -0
  141. package/src/web/table/table-cell.tsx +74 -0
  142. package/src/web/table/table-empty.tsx +108 -0
  143. package/src/web/table/table-footer.tsx +45 -0
  144. package/src/web/table/table-head.tsx +80 -0
  145. package/src/web/table/table-header.tsx +45 -0
  146. package/src/web/table/table-row.tsx +69 -0
  147. package/src/web/table/table.css +1 -0
  148. package/src/web/table/table.tsx +305 -0
  149. package/src/web/tabs/AI_GUIDE.md +150 -0
  150. package/src/web/tabs/index.ts +3 -0
  151. package/src/web/tabs/manifest.json +315 -0
  152. package/src/web/tabs/tabs.css +1 -0
  153. package/src/web/tabs/tabs.tsx +332 -0
  154. package/src/web/text/AI_GUIDE.md +129 -0
  155. package/src/web/text/index.ts +3 -0
  156. package/src/web/text/manifest.json +195 -0
  157. package/src/web/text/text.css +1 -0
  158. package/src/web/text/text.tsx +689 -0
  159. package/src/web/textarea/AI_GUIDE.md +141 -0
  160. package/src/web/textarea/index.ts +3 -0
  161. package/src/web/textarea/manifest.json +438 -0
  162. package/src/web/textarea/textarea.css +1 -0
  163. package/src/web/textarea/textarea.tsx +467 -0
  164. package/src/web/tooltip/AI_GUIDE.md +110 -0
  165. package/src/web/tooltip/index.ts +3 -0
  166. package/src/web/tooltip/manifest.json +222 -0
  167. package/src/web/tooltip/tooltip.css +1 -0
  168. package/src/web/tooltip/tooltip.tsx +423 -0
  169. package/src/webview/bottomsheet/AI_GUIDE.md +141 -0
  170. package/src/webview/bottomsheet/bottomsheet.css +1 -0
  171. package/src/webview/bottomsheet/bottomsheet.tsx +603 -0
  172. package/src/webview/bottomsheet/index.ts +4 -0
  173. package/src/webview/bottomsheet/manifest.json +377 -0
  174. package/src/webview/button/AI_GUIDE.md +79 -0
  175. package/src/webview/button/button-ios.css +1 -0
  176. package/src/webview/button/button-ios.tsx +138 -0
  177. package/src/webview/button/button-material.css +1 -0
  178. package/src/webview/button/button-material.tsx +138 -0
  179. package/src/webview/button/index.ts +7 -0
  180. package/src/webview/button/manifest.json +148 -0
  181. package/src/webview/index.ts +7 -0
  182. package/tailwind-preset.cjs +62 -0
  183. package/tailwind-preset.js +62 -0
  184. package/ttdk-manifest.json +10188 -0
@@ -0,0 +1,69 @@
1
+ "use client";
2
+ import * as React from "react";
3
+
4
+ export interface TableRowProps {
5
+ /**
6
+ * Inline CSS style kustom.
7
+ */
8
+ style?: React.CSSProperties;
9
+ /**
10
+ * Menandai baris sebagai aktif / terpilih (selected).
11
+ * @default false
12
+ */
13
+ selected?: boolean;
14
+
15
+ /**
16
+ * Efek hover saat kursor melayang di atas baris.
17
+ */
18
+ hoverable?: boolean;
19
+
20
+ /**
21
+ * Kustomisasi visual granular tr (UiProps).
22
+ */
23
+ ui?: UiProps;
24
+
25
+ /**
26
+ * Class CSS kustom.
27
+ */
28
+ className?: string;
29
+
30
+ /**
31
+ * Fungsi callback saat baris diklik.
32
+ */
33
+ onClick?: (event: any) => void;
34
+
35
+ /**
36
+ * Konten sel (TableCell atau TableHead).
37
+ */
38
+ children?: any;
39
+ }
40
+
41
+ /**
42
+ * Komponen baris tabel `<tr>` (Compound TableRow).
43
+ */
44
+
45
+ import { buildUiVars, UiProps } from "../../core/types";
46
+
47
+ function TableRow(props: TableRowProps) {
48
+ return (
49
+ <tr
50
+ className={`ttdk-table-row ${props.className || ""}`.trim()}
51
+ data-selected={props.selected ? "true" : "false"}
52
+ data-hoverable={props.hoverable !== false ? "true" : "false"}
53
+ onClick={(e) => {
54
+ if (props.onClick) {
55
+ props.onClick(e);
56
+ }
57
+ }}
58
+ style={{
59
+ ...buildUiVars(props.ui),
60
+ ...((props as any)["style"] || {}),
61
+ ...props.style,
62
+ }}
63
+ >
64
+ <>{props.children}</>
65
+ </tr>
66
+ );
67
+ }
68
+
69
+ export default TableRow;
@@ -0,0 +1 @@
1
+ .ttdk-table-wrapper{width:100%;font-family:var(--ttdk-font-sans);background:var(--ttdk-bg-card);border:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle);--table-corner-radius:var(--ttdk-ui-border-radius,var(--ttdk-radius-sm,8px));border-radius:var(--table-corner-radius);box-shadow:var(--ttdk-shadow-sm);box-sizing:border-box;transition:background-color .2s,border-color .2s;position:relative;overflow:auto}.ttdk-table-wrapper[data-rounded=none]{--table-corner-radius:var(--ttdk-radius-none,0px)}.ttdk-table-wrapper[data-rounded=xs]{--table-corner-radius:var(--ttdk-radius-xs,6px)}.ttdk-table-wrapper[data-rounded=sm]{--table-corner-radius:var(--ttdk-radius-sm,8px)}.ttdk-table-wrapper[data-rounded=md]{--table-corner-radius:var(--ttdk-radius-md,12px)}.ttdk-table-wrapper[data-rounded=lg]{--table-corner-radius:var(--ttdk-radius-lg,16px)}.ttdk-table-wrapper[data-rounded=xl],.ttdk-table-wrapper[data-rounded=full]{--table-corner-radius:var(--ttdk-radius-xl,24px)}.ttdk-table-wrapper.rounded-none{--table-corner-radius:0px!important}.ttdk-table-wrapper.rounded-xs,.ttdk-table-wrapper.rounded-sm{--table-corner-radius:var(--ttdk-radius-xs,6px)!important}.ttdk-table-wrapper.rounded,.ttdk-table-wrapper.rounded-md{--table-corner-radius:var(--ttdk-radius-sm,8px)!important}.ttdk-table-wrapper.rounded-lg{--table-corner-radius:var(--ttdk-radius-md,12px)!important}.ttdk-table-wrapper.rounded-xl{--table-corner-radius:var(--ttdk-radius-lg,16px)!important}.ttdk-table-wrapper.rounded-2xl{--table-corner-radius:var(--ttdk-radius-xl,24px)!important}.ttdk-table-wrapper[data-shadow=none]{box-shadow:none}.ttdk-table-wrapper[data-shadow=sm]{box-shadow:var(--ttdk-shadow-sm)}.ttdk-table-wrapper[data-shadow=md]{box-shadow:var(--ttdk-shadow-md)}.ttdk-table-wrapper[data-shadow=lg]{box-shadow:var(--ttdk-shadow-lg)}.dark .ttdk-table-wrapper[data-shadow=none]{box-shadow:none}.dark .ttdk-table-wrapper[data-shadow=sm]{box-shadow:var(--ttdk-shadow-sm)}.dark .ttdk-table-wrapper[data-shadow=md]{box-shadow:var(--ttdk-shadow-md)}.dark .ttdk-table-wrapper[data-shadow=lg]{box-shadow:var(--ttdk-shadow-lg)}.ttdk-table-wrapper.shadow-none{box-shadow:none!important}.ttdk-table-wrapper.shadow-sm,.ttdk-table-wrapper.shadow{box-shadow:var(--ttdk-shadow-sm)!important}.ttdk-table-wrapper.shadow-md{box-shadow:var(--ttdk-shadow-md)!important}.ttdk-table-wrapper.shadow-lg,.ttdk-table-wrapper.shadow-xl{box-shadow:var(--ttdk-shadow-lg)!important}.dark .ttdk-table-wrapper{background:var(--ttdk-bg-card);border-color:var(--ttdk-stroke-subtle);box-shadow:var(--ttdk-shadow-sm)}.ttdk-table-loading-overlay{background:color-mix(in srgb, var(--ttdk-bg-card) 75%, transparent);z-index:10;backdrop-filter:blur(2px);justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.dark .ttdk-table-loading-overlay{background:color-mix(in srgb, var(--ttdk-bg-card) 75%, transparent)}.ttdk-table-spinner{fill:none;stroke:currentColor;stroke-width:2.2px;stroke-linecap:round;width:24px;height:24px;color:var(--ttdk-brand-default);animation:1.2s steps(12,end) infinite ttdk-table-spin}.ttdk-table-wrapper[data-size=sm] .ttdk-table-spinner,.ttdk-table-wrapper:has(.ttdk-table[data-size=sm]) .ttdk-table-spinner{width:18px;height:18px}.ttdk-table-wrapper[data-size=md] .ttdk-table-spinner,.ttdk-table-wrapper:has(.ttdk-table[data-size=md]) .ttdk-table-spinner{width:24px;height:24px}.ttdk-table-wrapper[data-size=lg] .ttdk-table-spinner,.ttdk-table-wrapper:has(.ttdk-table[data-size=lg]) .ttdk-table-spinner{width:32px;height:32px}@keyframes ttdk-table-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.ttdk-table{caption-side:bottom;border-collapse:collapse;text-align:left;width:100%;font-size:13px;line-height:1.5}.ttdk-table-wrapper[data-variant=clean],.ttdk-table-wrapper:has(.ttdk-table[data-variant=clean]){box-shadow:none;background:0 0;border:none;border-radius:0}.dark .ttdk-table-wrapper[data-variant=clean],.dark .ttdk-table-wrapper:has(.ttdk-table[data-variant=clean]){box-shadow:none;background:0 0;border:none}.ttdk-table-wrapper[data-variant=clean] .ttdk-table-header,.ttdk-table-wrapper:has(.ttdk-table[data-variant=clean]) .ttdk-table-header,.dark .ttdk-table-wrapper[data-variant=clean] .ttdk-table-header,.dark .ttdk-table-wrapper:has(.ttdk-table[data-variant=clean]) .ttdk-table-header{background:0 0}.ttdk-table[data-variant=clean]{border:none}.ttdk-table[data-sticky-header=true] .ttdk-table-head,.ttdk-table-wrapper[data-sticky-header=true] .ttdk-table-head,.ttdk-table-wrapper:has(.ttdk-table[data-sticky-header=true]) .ttdk-table-head{z-index:10;background:var(--ttdk-bg-secondary-disabled);box-shadow:inset 0 -1px 0 var(--ttdk-stroke-subtle);position:sticky;top:0}.dark .ttdk-table[data-sticky-header=true] .ttdk-table-head,.dark .ttdk-table-wrapper[data-sticky-header=true] .ttdk-table-head,.dark .ttdk-table-wrapper:has(.ttdk-table[data-sticky-header=true]) .ttdk-table-head{background:var(--ttdk-bg-secondary-disabled);box-shadow:inset 0 -1px 0 var(--ttdk-stroke-subtle)}.ttdk-table-wrapper[data-variant=clean][data-sticky-header=true] .ttdk-table-head,.ttdk-table-wrapper[data-variant=clean]:has(.ttdk-table[data-sticky-header=true]) .ttdk-table-head,.ttdk-table[data-variant=clean][data-sticky-header=true] .ttdk-table-head,.dark .ttdk-table-wrapper[data-variant=clean][data-sticky-header=true] .ttdk-table-head,.dark .ttdk-table-wrapper[data-variant=clean]:has(.ttdk-table[data-sticky-header=true]) .ttdk-table-head,.dark .ttdk-table[data-variant=clean][data-sticky-header=true] .ttdk-table-head{background:var(--ttdk-bg-card);box-shadow:inset 0 -1px 0 var(--ttdk-stroke-subtle)}.ttdk-table[data-size=sm] th,.ttdk-table[data-size=sm] td{padding:8px 12px;font-size:12px}.ttdk-table[data-size=md] th,.ttdk-table[data-size=md] td{padding:14px 16px;font-size:13px}.ttdk-table[data-size=lg] th,.ttdk-table[data-size=lg] td{padding:18px 20px;font-size:14px}.ttdk-table-header{background:var(--ttdk-bg-secondary-disabled);border-bottom:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle)}.dark .ttdk-table-header{background:var(--ttdk-bg-secondary-disabled);border-bottom-color:var(--ttdk-stroke-subtle)}.ttdk-table-head{height:44px;color:var(--ttdk-text-icon-secondary);letter-spacing:.2px;vertical-align:middle;border-bottom:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle);white-space:nowrap;user-select:none;padding:12px 16px;font-size:12px;font-weight:600;transition:background-color .15s,color .15s}.dark .ttdk-table-head{color:var(--ttdk-text-icon-secondary);border-bottom-color:var(--ttdk-stroke-subtle)}.ttdk-table-head[data-sortable=true]{cursor:pointer}.ttdk-table-head[data-sortable=true]:hover,.dark .ttdk-table-head[data-sortable=true]:hover{background:var(--ttdk-bg-secondary-disabled);color:var(--ttdk-text-icon-primary)}.ttdk-th-inner{align-items:center;gap:6px;display:inline-flex}.ttdk-table-body{border-bottom:0}.ttdk-table-row{border-bottom:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle);transition:background-color .15s}.dark .ttdk-table-row{border-bottom-color:var(--ttdk-stroke-subtle)}.ttdk-table-row:last-child{border-bottom:none}.ttdk-table[data-hoverable=true] .ttdk-table-row:hover,.ttdk-table-row[data-hoverable=true]:hover,.dark .ttdk-table[data-hoverable=true] .ttdk-table-row:hover,.dark .ttdk-table-row[data-hoverable=true]:hover,.ttdk-table[data-variant=striped] .ttdk-table-body .ttdk-table-row:nth-child(2n),.dark .ttdk-table[data-variant=striped] .ttdk-table-body .ttdk-table-row:nth-child(2n){background:var(--ttdk-bg-secondary-disabled)}.ttdk-table-row[data-selected=true]{background:var(--ttdk-bg-status-info-subtle)!important}.dark .ttdk-table-row[data-selected=true]{background:var(--ttdk-color-blue-900)!important}.ttdk-table-cell{color:var(--ttdk-ui-color,var(--ttdk-text-icon-primary));vertical-align:middle;padding:14px 16px}.dark .ttdk-table-cell{color:var(--ttdk-ui-color,var(--ttdk-text-icon-primary))}.ttdk-table-footer{background:var(--ttdk-bg-secondary-disabled);border-top:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle);color:var(--ttdk-ui-color,var(--ttdk-text-icon-primary));font-weight:500}.dark .ttdk-table-footer{background:var(--ttdk-bg-secondary-disabled);border-top-color:var(--ttdk-stroke-subtle);color:var(--ttdk-ui-color,var(--ttdk-text-icon-primary))}.ttdk-table-caption{color:var(--ttdk-text-icon-secondary);text-align:center;margin-top:12px;padding:0 16px 12px;font-size:12px}.dark .ttdk-table-caption{color:var(--ttdk-text-icon-secondary)}.ttdk-table-empty-wrapper{text-align:center;flex-direction:column;justify-content:center;align-items:center;padding:56px 24px;display:flex}.ttdk-table-empty-title{color:var(--ttdk-text-icon-primary);margin:0;font-size:14px;font-weight:700}.dark .ttdk-table-empty-title{color:var(--ttdk-text-icon-primary)}.ttdk-table-empty-desc{color:var(--ttdk-text-icon-secondary);margin:4px 0 0;font-size:12px}.dark .ttdk-table-empty-desc{color:var(--ttdk-text-icon-secondary)}.ttdk-table-empty-action{color:var(--ttdk-brand-default);cursor:pointer;border-radius:var(--ttdk-radius-input-sm);background:0 0;border:none;margin-top:12px;padding:4px 8px;font-size:13px;font-weight:600;transition:color .15s}.ttdk-table-empty-action:hover{text-decoration:underline}.dark .ttdk-table-empty-action{color:var(--ttdk-brand-default)}.ttdk-cell-title-group{flex-direction:column;gap:2px;display:flex}.ttdk-cell-main-title{color:var(--ttdk-text-icon-primary);font-size:13px;font-weight:600}.dark .ttdk-cell-main-title{color:var(--ttdk-text-icon-primary)}.ttdk-cell-subtitle{color:var(--ttdk-text-icon-secondary);font-size:11px}.dark .ttdk-cell-subtitle{color:var(--ttdk-text-icon-secondary)}.ttdk-format-badges{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.ttdk-format-tag{border-radius:var(--ttdk-radius-input-sm);background:var(--ttdk-bg-secondary-disabled);color:var(--ttdk-text-icon-primary);border:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle);padding:2px 6px;font-size:11px;font-weight:600}.dark .ttdk-format-tag{background:var(--ttdk-bg-secondary-disabled);border-color:var(--ttdk-stroke-subtle);color:var(--ttdk-text-icon-primary)}.ttdk-view-count{color:var(--ttdk-text-icon-secondary);align-items:center;gap:6px;font-size:12px;display:flex}.dark .ttdk-view-count{color:var(--ttdk-text-icon-secondary)}.ttdk-btn-fav{border-radius:var(--ttdk-radius-xs);border:var(--ttdk-stroke-width-thin) solid var(--ttdk-stroke-subtle);width:32px;height:32px;color:var(--ttdk-text-icon-secondary);cursor:pointer;background:0 0;justify-content:center;align-items:center;padding:0;transition:all .15s;display:inline-flex}.ttdk-btn-fav:hover{background:var(--ttdk-bg-secondary-disabled);border-color:var(--ttdk-stroke-strong)}.dark .ttdk-btn-fav{border-color:var(--ttdk-stroke-subtle);color:var(--ttdk-text-icon-secondary)}.dark .ttdk-btn-fav:hover{background:var(--ttdk-bg-secondary-disabled);color:var(--ttdk-text-icon-primary)}.ttdk-btn-fav.active{background:var(--ttdk-brand-default);border-color:var(--ttdk-brand-default);color:var(--ttdk-color-neutral-white)}
@@ -0,0 +1,305 @@
1
+ import * as React from "react";
2
+
3
+ export type TableUiProps = UiProps;
4
+ export interface TableProps {
5
+ /**
6
+ * Varian tampilan visual tabel.
7
+ * - `'default'`: Tampilan standar dengan latar bersih dan bingkai kartu.
8
+ * - `'striped'`: Tampilan selang-seling (zebra).
9
+ * - `'clean'`: Tampilan minimalis tanpa border luar dan tanpa shadow.
10
+ * @default 'default'
11
+ */
12
+ variant?: "default" | "striped" | "clean";
13
+
14
+ /**
15
+ * Kerapatan / ukuran tinggi baris tabel.
16
+ * - `'sm'`: Kompak (padat).
17
+ * - `'md'`: Standar.
18
+ * - `'lg'`: Lega.
19
+ * @default 'md'
20
+ */
21
+ size?: "sm" | "md" | "lg";
22
+
23
+ /**
24
+ * Sudut kelengkungan radius tabel.
25
+ * - Preset: `'none'` | `'xs'` | `'sm'` | `'md'` | `'lg'` | `'xl'` | `'full'`
26
+ * - Nilai custom: `'12px'`, `'1rem'`, atau angka `12`
27
+ * @default 'sm'
28
+ */
29
+ rounded?:
30
+ | "none"
31
+ | "xs"
32
+ | "sm"
33
+ | "md"
34
+ | "lg"
35
+ | "xl"
36
+ | "full"
37
+ | (string & {})
38
+ | number;
39
+
40
+ /**
41
+ * Bayangan elevasi kontainer tabel.
42
+ * - Preset: `'none'` | `'sm'` | `'md'` | `'lg'`
43
+ * - Nilai custom: CSS box-shadow string (contoh: `'0 4px 20px rgba(0,0,0,0.1)'`)
44
+ * @default 'sm'
45
+ */
46
+ shadow?: "none" | "sm" | "md" | "lg" | (string & {});
47
+
48
+ /**
49
+ * Lebar minimum elemen table di dalam wrapper untuk menjaga susunan kolom dan memicu horizontal scroll.
50
+ * Contoh: `700`, `'700px'`, `'max-content'`
51
+ */
52
+ minWidth?: string | number;
53
+
54
+ /**
55
+ * Ketinggian maksimum kontainer tabel untuk memicu scroll vertikal internal (sangat direkomendasikan saat stickyHeader aktif).
56
+ * Contoh: `280`, `'280px'`, `'50vh'`
57
+ */
58
+ maxHeight?: string | number;
59
+
60
+ /**
61
+ * Efek hover saat kursor melayang di atas baris tabel.
62
+ * @default true
63
+ */
64
+ hoverable?: boolean;
65
+
66
+ /**
67
+ * Membuat header tabel menempel di atas (sticky) saat konten di-scroll.
68
+ * @default false
69
+ */
70
+ stickyHeader?: boolean;
71
+
72
+ /**
73
+ * Menampilkan spinner loading overlay di atas tabel.
74
+ * @default false
75
+ */
76
+ loading?: boolean;
77
+
78
+ /**
79
+ * Teks caption aksesibilitas untuk tabel (dirender sebagai elemen `<caption>`).
80
+ */
81
+ caption?: string;
82
+
83
+ /**
84
+ * Inline CSS style object native.
85
+ */
86
+ style?: React.CSSProperties;
87
+
88
+ /**
89
+ * Kustomisasi visual granular root kontainer wrapper (.ttdk-table-wrapper) melalui UiProps.
90
+ */
91
+ ui?: UiProps;
92
+
93
+ /**
94
+ * Style kustom untuk elemen table (table.ttdk-table) melalui UiProps.
95
+ */
96
+ tableStyle?: UiProps;
97
+
98
+ /**
99
+ * Class CSS kustom untuk elemen table (table.ttdk-table).
100
+ */
101
+ tableClass?: string;
102
+
103
+ /**
104
+ * Class CSS kustom untuk kontainer wrapper luar.
105
+ */
106
+ className?: string;
107
+
108
+ /**
109
+ * Konten anak (TableHeader, TableBody, TableFooter, TableCaption).
110
+ */
111
+ children?: any;
112
+ }
113
+
114
+ /**
115
+ * Komponen kontainer utama tabel (Compound Table ala Shadcn UI).
116
+ */
117
+
118
+ import { buildUiVars, UiProps } from "../../core/types";
119
+
120
+ function Table(props: TableProps) {
121
+ return (
122
+ <div
123
+ className={`ttdk-table-wrapper ${props.className || ""}`.trim()}
124
+ data-loading={props.loading ? "true" : undefined}
125
+ data-variant={props.variant || "default"}
126
+ data-size={props.size || "md"}
127
+ data-sticky-header={props.stickyHeader ? "true" : undefined}
128
+ data-rounded={
129
+ props.rounded &&
130
+ ["none", "xs", "sm", "md", "lg", "xl", "full"].includes(
131
+ props.rounded as string
132
+ )
133
+ ? props.rounded
134
+ : undefined
135
+ }
136
+ data-shadow={
137
+ props.shadow &&
138
+ ["none", "sm", "md", "lg"].includes(props.shadow as string)
139
+ ? props.shadow
140
+ : undefined
141
+ }
142
+ style={{
143
+ ...(props.maxHeight
144
+ ? {
145
+ maxHeight:
146
+ typeof props.maxHeight === "number"
147
+ ? `${props.maxHeight}px`
148
+ : props.maxHeight,
149
+ }
150
+ : {}),
151
+ ...(typeof props.rounded === "number"
152
+ ? {
153
+ "--table-corner-radius": `${props.rounded}px`,
154
+ }
155
+ : props.rounded &&
156
+ !["none", "xs", "sm", "md", "lg", "xl", "full"].includes(
157
+ props.rounded as string
158
+ )
159
+ ? {
160
+ "--table-corner-radius": props.rounded,
161
+ }
162
+ : {}),
163
+ ...(props.shadow &&
164
+ !["none", "sm", "md", "lg"].includes(props.shadow as string)
165
+ ? {
166
+ boxShadow: props.shadow,
167
+ }
168
+ : {}),
169
+ ...buildUiVars(props.ui),
170
+ ...((props as any)["style"] || {}),
171
+ ...props.style,
172
+ }}
173
+ >
174
+ {props.loading ? (
175
+ <div className="ttdk-table-loading-overlay" aria-hidden="true">
176
+ <svg className="ttdk-table-spinner" viewBox="0 0 24 24">
177
+ <line
178
+ x1="12"
179
+ y1="2.5"
180
+ x2="12"
181
+ y2="6.5"
182
+ opacity="0.175"
183
+ transform="rotate(0 12 12)"
184
+ />
185
+ <line
186
+ x1="12"
187
+ y1="2.5"
188
+ x2="12"
189
+ y2="6.5"
190
+ opacity="0.25"
191
+ transform="rotate(30 12 12)"
192
+ />
193
+ <line
194
+ x1="12"
195
+ y1="2.5"
196
+ x2="12"
197
+ y2="6.5"
198
+ opacity="0.325"
199
+ transform="rotate(60 12 12)"
200
+ />
201
+ <line
202
+ x1="12"
203
+ y1="2.5"
204
+ x2="12"
205
+ y2="6.5"
206
+ opacity="0.4"
207
+ transform="rotate(90 12 12)"
208
+ />
209
+ <line
210
+ x1="12"
211
+ y1="2.5"
212
+ x2="12"
213
+ y2="6.5"
214
+ opacity="0.475"
215
+ transform="rotate(120 12 12)"
216
+ />
217
+ <line
218
+ x1="12"
219
+ y1="2.5"
220
+ x2="12"
221
+ y2="6.5"
222
+ opacity="0.55"
223
+ transform="rotate(150 12 12)"
224
+ />
225
+ <line
226
+ x1="12"
227
+ y1="2.5"
228
+ x2="12"
229
+ y2="6.5"
230
+ opacity="0.625"
231
+ transform="rotate(180 12 12)"
232
+ />
233
+ <line
234
+ x1="12"
235
+ y1="2.5"
236
+ x2="12"
237
+ y2="6.5"
238
+ opacity="0.7"
239
+ transform="rotate(210 12 12)"
240
+ />
241
+ <line
242
+ x1="12"
243
+ y1="2.5"
244
+ x2="12"
245
+ y2="6.5"
246
+ opacity="0.775"
247
+ transform="rotate(240 12 12)"
248
+ />
249
+ <line
250
+ x1="12"
251
+ y1="2.5"
252
+ x2="12"
253
+ y2="6.5"
254
+ opacity="0.85"
255
+ transform="rotate(270 12 12)"
256
+ />
257
+ <line
258
+ x1="12"
259
+ y1="2.5"
260
+ x2="12"
261
+ y2="6.5"
262
+ opacity="0.925"
263
+ transform="rotate(300 12 12)"
264
+ />
265
+ <line
266
+ x1="12"
267
+ y1="2.5"
268
+ x2="12"
269
+ y2="6.5"
270
+ opacity="1"
271
+ transform="rotate(330 12 12)"
272
+ />
273
+ </svg>
274
+ </div>
275
+ ) : null}
276
+ <table
277
+ className={`ttdk-table ${props.tableClass || ""}`.trim()}
278
+ data-variant={props.variant || "default"}
279
+ data-size={props.size || "md"}
280
+ data-hoverable={props.hoverable !== false ? "true" : "false"}
281
+ data-sticky-header={props.stickyHeader ? "true" : undefined}
282
+ style={{
283
+ ...(props.minWidth
284
+ ? {
285
+ minWidth:
286
+ typeof props.minWidth === "number"
287
+ ? `${props.minWidth}px`
288
+ : props.minWidth,
289
+ }
290
+ : {}),
291
+ ...buildUiVars(props.tableStyle),
292
+ }}
293
+ >
294
+ {props.caption ? (
295
+ <caption className="ttdk-table-caption">{props.caption}</caption>
296
+ ) : null}
297
+ <>{props.children}</>
298
+ </table>
299
+ </div>
300
+ );
301
+ }
302
+
303
+ export default Table;
304
+
305
+ export { Table };
@@ -0,0 +1,150 @@
1
+ # <Tabs /> — TTDK Component Reference
2
+
3
+ Komponen Tabs untuk navigasi multi-panel dengan orientasi Horizontal & Vertikal, varian Line, Pills, dan Enclosed.
4
+
5
+ ## 1. Stylesheets & Theming (Pure CSS)
6
+ Import the corresponding stylesheet for the theme you wish to use:
7
+ - **COMMON Theme**: `import "@ttdk-design-system/library-<react|vue|svelte>/web/tabs/tabs.css";`
8
+
9
+ ## 2. Subpath Component Import
10
+ ```ts
11
+ // React
12
+ import Tabs from "@ttdk-design-system/library-react/web/tabs";
13
+
14
+ // Vue 3
15
+ import Tabs from "@ttdk-design-system/library-vue/web/tabs";
16
+
17
+ // Svelte
18
+ import Tabs from "@ttdk-design-system/library-svelte/web/tabs";
19
+ ```
20
+
21
+ ## 3. Props & API Reference
22
+
23
+ | Prop | Type | Default | Description |
24
+ | :--- | :--- | :--- | :--- |
25
+ | `items` | `TabItem[]` | `-` | Daftar tab items yang akan dirender. |
26
+ | `value?` | `string` | `-` | Nilai tab yang sedang aktif (v-model / controlled value). |
27
+ | `defaultValue?` | `string` | `-` | Nilai tab default saat pertama kali dirender (uncontrolled initial value). |
28
+ | `orientation?` | `'horizontal' | 'vertical'` | `horizontal` | Orientasi tata letak tab. - `'horizontal'`: Tab berjejer ke samping dengan garis indikator di bawah (standar). - `'vertical'`: Tab berjejer ke bawah dalam kolom dengan garis indikator di samping. |
29
+ | `variant?` | `'line' | 'pills'` | `line` | Varian visual tampilan tab. - `'line'`: Garis indikator bawah/samping minimalis elegan (sesuai desain TTDK). - `'pills'`: Bentuk kapsul/tombol latar belakang penuh ala Shadcn / Nuxt UI. |
30
+ | `size?` | `'sm' | 'md' | 'lg'` | `md` | Ukuran proporsional tab (tinggi, padding, ukuran font). - `'sm'`: Kecil (12px font, compact padding). - `'md'`: Standar (14px font, regular padding). - `'lg'`: Besar (16px font, spacious padding). |
31
+ | `fitted?` | `boolean` | `false` | Membuat lebar setiap tab mengisi rata seluruh ruang container (full width / equal width). |
32
+ | `rounded?` | `'none' | 'sm' | 'md' | 'lg' | 'full'` | `md` | Sudut kelengkungan (khusus untuk varian 'pills'). - `'none'`: Sudut 0px. - `'sm'`: Sudut 4px. - `'md'`: Sudut 6px. - `'lg'`: Sudut 8px. - `'full'`: Sudut 9999px. |
33
+ | `lazy?` | `boolean` | `false` | Hanya me-render konten panel tab saat tab tersebut aktif (lazy rendering). Berguna untuk menghemat performa saat tab memiliki konten berat. |
34
+ | `style?` | `any` | `-` | Inline CSS style object native. |
35
+ | `ui?` | `UiProps` | `-` | Kustomisasi visual granular root container (UiProps). |
36
+ | `listStyle?` | `UiProps` | `-` | Style kustom untuk container tab list (UiProps). |
37
+ | `listClass?` | `string` | `-` | Class CSS kustom untuk container tab list. |
38
+ | `tabStyle?` | `UiProps` | `-` | Style kustom untuk tombol tab item (UiProps). |
39
+ | `tabClass?` | `string` | `-` | Class CSS kustom untuk tombol tab item. |
40
+ | `activeTabStyle?` | `UiProps` | `-` | Style kustom untuk tombol tab item saat aktif (UiProps). |
41
+ | `activeTabClass?` | `string` | `-` | Class CSS kustom untuk tombol tab item saat aktif. |
42
+ | `indicatorStyle?` | `UiProps` | `-` | Style kustom untuk garis indikator tab (UiProps). |
43
+ | `indicatorClass?` | `string` | `-` | Class CSS kustom untuk garis indikator tab. |
44
+ | `badgeStyle?` | `UiProps` | `-` | Style kustom untuk badge tab (UiProps). |
45
+ | `badgeClass?` | `string` | `-` | Class CSS kustom untuk badge tab. |
46
+ | `panelStyle?` | `UiProps` | `-` | Style kustom untuk panel konten tab (UiProps). |
47
+ | `panelClass?` | `string` | `-` | Class CSS kustom untuk panel konten tab. |
48
+ | `onChange?` | `(value: string) => void` | `-` | Callback event saat pengguna mengganti tab aktif. |
49
+ | `className?` | `string` | `-` | Class CSS kustom. |
50
+ | `children?` | `any` | `-` | Konten kustom atau slot anak. |
51
+
52
+ ### Sub-interface: `TabItem`
53
+
54
+ | Field | Type | Default | Description |
55
+ | :--- | :--- | :--- | :--- |
56
+ | `label` | `string` | `-` | Label teks yang ditampilkan pada tab item. |
57
+ | `value` | `string` | `-` | Identifier unik / nilai aktif untuk tab ini. |
58
+ | `icon?` | `any` | `-` | Ikon atau emoji opsional di samping label teks. |
59
+ | `badge?` | `string | number` | `-` | Badge teks atau counter angka opsional (misal: '12', 'Baru'). |
60
+ | `disabled?` | `boolean` | `false` | Menonaktifkan tab item dari interaksi klik. |
61
+ | `content?` | `any` | `-` | Konten tab opsional jika ingin menggunakan panel terintegrasi. |
62
+
63
+ ## 4. Usage Examples
64
+
65
+ ### React Example
66
+ ```tsx
67
+ import { useState } from "react";
68
+ import Tabs from "@ttdk-design-system/library-react/web/tabs";
69
+ import "@ttdk-design-system/library-react/web/tabs/tabs.css";
70
+
71
+ export function Example() {
72
+ const [activeTab, setActiveTab] = useState("overview");
73
+
74
+ const tabItems = [
75
+ { label: "Ringkasan", value: "overview", badge: 4 },
76
+ { label: "Data Pasien", value: "patients" },
77
+ { label: "Integrasi API", value: "api" },
78
+ { label: "Pengaturan", value: "settings", disabled: true }
79
+ ];
80
+
81
+ return (
82
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
83
+ <Tabs
84
+ items={tabItems}
85
+ value={activeTab}
86
+ variant="line"
87
+ onChange={(val) => setActiveTab(val)}
88
+ />
89
+ <div>Konten aktif tab: {activeTab}</div>
90
+ </div>
91
+ );
92
+ }
93
+ ```
94
+
95
+ ### Vue 3 Example
96
+ ```vue
97
+ <script setup lang="ts">
98
+ import { ref } from "vue";
99
+ import Tabs from "@ttdk-design-system/library-vue/web/tabs";
100
+ import "@ttdk-design-system/library-vue/web/tabs/tabs.css";
101
+
102
+ const activeTab = ref("overview");
103
+
104
+ const tabItems = [
105
+ { label: "Ringkasan", value: "overview", badge: 4 },
106
+ { label: "Data Pasien", value: "patients" },
107
+ { label: "Integrasi API", value: "api" },
108
+ { label: "Pengaturan", value: "settings", disabled: true }
109
+ ];
110
+ </script>
111
+
112
+ <template>
113
+ <div style="display: flex; flex-direction: column; gap: 16px;">
114
+ <Tabs
115
+ :items="tabItems"
116
+ :value="activeTab"
117
+ variant="line"
118
+ @change="(val: string) => (activeTab = val)"
119
+ />
120
+ <div>Konten aktif tab: {{ activeTab }}</div>
121
+ </div>
122
+ </template>
123
+ ```
124
+
125
+ ### Svelte Example
126
+ ```svelte
127
+ <script lang="ts">
128
+ import Tabs from "@ttdk-design-system/library-svelte/web/tabs";
129
+ import "@ttdk-design-system/library-svelte/web/tabs/tabs.css";
130
+
131
+ let activeTab = "overview";
132
+
133
+ const tabItems = [
134
+ { label: "Ringkasan", value: "overview", badge: 4 },
135
+ { label: "Data Pasien", value: "patients" },
136
+ { label: "Integrasi API", value: "api" },
137
+ { label: "Pengaturan", value: "settings", disabled: true }
138
+ ];
139
+ </script>
140
+
141
+ <div style="display: flex; flex-direction: column; gap: 16px;">
142
+ <Tabs
143
+ items={tabItems}
144
+ value={activeTab}
145
+ variant="line"
146
+ on:change={(e) => (activeTab = e.detail)}
147
+ />
148
+ <div>Konten aktif tab: {activeTab}</div>
149
+ </div>
150
+ ```
@@ -0,0 +1,3 @@
1
+ export { default as Tabs } from './tabs';
2
+ export { default } from './tabs';
3
+ export * from './tabs'