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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/AI_GUIDE.md +6518 -0
  2. package/llms.txt +6518 -0
  3. package/package.json +1098 -4
  4. package/src/core/index.ts +2 -0
  5. package/src/core/tailwind-preset.cjs +62 -0
  6. package/src/core/tailwind-preset.ts +85 -0
  7. package/src/core/theme/tokens.css +663 -0
  8. package/src/core/types.ts +836 -0
  9. package/src/index.ts +17 -0
  10. package/src/tailwind-preset.cjs +62 -0
  11. package/src/tailwind-preset.ts +85 -0
  12. package/src/types.ts +1 -0
  13. package/src/web/accordion/AI_GUIDE.md +149 -0
  14. package/src/web/accordion/accordion.css +1 -0
  15. package/src/web/accordion/accordion.tsx +430 -0
  16. package/src/web/accordion/index.ts +3 -0
  17. package/src/web/accordion/manifest.json +351 -0
  18. package/src/web/alert/AI_GUIDE.md +139 -0
  19. package/src/web/alert/alert.css +1 -0
  20. package/src/web/alert/alert.tsx +318 -0
  21. package/src/web/alert/index.ts +3 -0
  22. package/src/web/alert/manifest.json +240 -0
  23. package/src/web/avatar/AI_GUIDE.md +118 -0
  24. package/src/web/avatar/avatar.css +1 -0
  25. package/src/web/avatar/avatar.tsx +233 -0
  26. package/src/web/avatar/index.ts +3 -0
  27. package/src/web/avatar/manifest.json +195 -0
  28. package/src/web/badge/AI_GUIDE.md +94 -0
  29. package/src/web/badge/badge.css +1 -0
  30. package/src/web/badge/badge.tsx +140 -0
  31. package/src/web/badge/index.ts +2 -0
  32. package/src/web/badge/manifest.json +141 -0
  33. package/src/web/banner/AI_GUIDE.md +130 -0
  34. package/src/web/banner/banner.css +1 -0
  35. package/src/web/banner/banner.tsx +334 -0
  36. package/src/web/banner/index.ts +3 -0
  37. package/src/web/banner/manifest.json +240 -0
  38. package/src/web/breadcrumb/AI_GUIDE.md +120 -0
  39. package/src/web/breadcrumb/breadcrumb.css +1 -0
  40. package/src/web/breadcrumb/breadcrumb.tsx +306 -0
  41. package/src/web/breadcrumb/index.ts +3 -0
  42. package/src/web/breadcrumb/manifest.json +225 -0
  43. package/src/web/button/AI_GUIDE.md +121 -0
  44. package/src/web/button/button.css +1 -0
  45. package/src/web/button/button.tsx +287 -0
  46. package/src/web/button/index.ts +2 -0
  47. package/src/web/button/manifest.json +177 -0
  48. package/src/web/calendar/AI_GUIDE.md +151 -0
  49. package/src/web/calendar/calendar.css +1 -0
  50. package/src/web/calendar/calendar.tsx +1611 -0
  51. package/src/web/calendar/index.ts +3 -0
  52. package/src/web/calendar/manifest.json +470 -0
  53. package/src/web/card/AI_GUIDE.md +133 -0
  54. package/src/web/card/card.css +1 -0
  55. package/src/web/card/card.tsx +408 -0
  56. package/src/web/card/index.ts +4 -0
  57. package/src/web/card/manifest.json +357 -0
  58. package/src/web/checkbox/AI_GUIDE.md +146 -0
  59. package/src/web/checkbox/checkbox.css +1 -0
  60. package/src/web/checkbox/checkbox.tsx +307 -0
  61. package/src/web/checkbox/index.ts +2 -0
  62. package/src/web/checkbox/manifest.json +294 -0
  63. package/src/web/chip/AI_GUIDE.md +186 -0
  64. package/src/web/chip/chip.css +1 -0
  65. package/src/web/chip/chip.tsx +230 -0
  66. package/src/web/chip/index.ts +2 -0
  67. package/src/web/chip/manifest.json +186 -0
  68. package/src/web/dropdown/AI_GUIDE.md +167 -0
  69. package/src/web/dropdown/dropdown.css +1 -0
  70. package/src/web/dropdown/dropdown.tsx +1274 -0
  71. package/src/web/dropdown/index.ts +3 -0
  72. package/src/web/dropdown/manifest.json +576 -0
  73. package/src/web/flex/AI_GUIDE.md +113 -0
  74. package/src/web/flex/flex-item.tsx +97 -0
  75. package/src/web/flex/flex.css +1 -0
  76. package/src/web/flex/flex.tsx +108 -0
  77. package/src/web/flex/index.ts +5 -0
  78. package/src/web/flex/manifest.json +162 -0
  79. package/src/web/form/index.ts +7 -0
  80. package/src/web/grid/AI_GUIDE.md +112 -0
  81. package/src/web/grid/grid-item.tsx +112 -0
  82. package/src/web/grid/grid.css +1 -0
  83. package/src/web/grid/grid.tsx +99 -0
  84. package/src/web/grid/index.ts +5 -0
  85. package/src/web/grid/manifest.json +153 -0
  86. package/src/web/index.ts +86 -0
  87. package/src/web/input/AI_GUIDE.md +159 -0
  88. package/src/web/input/index.ts +3 -0
  89. package/src/web/input/input.css +1 -0
  90. package/src/web/input/input.tsx +537 -0
  91. package/src/web/input/manifest.json +465 -0
  92. package/src/web/input-number/AI_GUIDE.md +164 -0
  93. package/src/web/input-number/index.ts +3 -0
  94. package/src/web/input-number/input-number.css +1 -0
  95. package/src/web/input-number/input-number.tsx +1193 -0
  96. package/src/web/input-number/manifest.json +575 -0
  97. package/src/web/modal/AI_GUIDE.md +171 -0
  98. package/src/web/modal/index.ts +3 -0
  99. package/src/web/modal/manifest.json +375 -0
  100. package/src/web/modal/modal.css +1 -0
  101. package/src/web/modal/modal.tsx +571 -0
  102. package/src/web/pagination/AI_GUIDE.md +148 -0
  103. package/src/web/pagination/index.ts +21 -0
  104. package/src/web/pagination/manifest.json +432 -0
  105. package/src/web/pagination/pagination-content.tsx +45 -0
  106. package/src/web/pagination/pagination-ellipsis.tsx +54 -0
  107. package/src/web/pagination/pagination-first.tsx +155 -0
  108. package/src/web/pagination/pagination-item.tsx +45 -0
  109. package/src/web/pagination/pagination-last.tsx +155 -0
  110. package/src/web/pagination/pagination-link.tsx +121 -0
  111. package/src/web/pagination/pagination-next.tsx +158 -0
  112. package/src/web/pagination/pagination-previous.tsx +158 -0
  113. package/src/web/pagination/pagination.css +1 -0
  114. package/src/web/pagination/pagination.tsx +687 -0
  115. package/src/web/popover/AI_GUIDE.md +163 -0
  116. package/src/web/popover/index.ts +3 -0
  117. package/src/web/popover/manifest.json +396 -0
  118. package/src/web/popover/popover.css +1 -0
  119. package/src/web/popover/popover.tsx +702 -0
  120. package/src/web/radio/AI_GUIDE.md +155 -0
  121. package/src/web/radio/index.ts +2 -0
  122. package/src/web/radio/manifest.json +294 -0
  123. package/src/web/radio/radio.css +1 -0
  124. package/src/web/radio/radio.tsx +290 -0
  125. package/src/web/selectbox/AI_GUIDE.md +216 -0
  126. package/src/web/selectbox/index.ts +3 -0
  127. package/src/web/selectbox/manifest.json +477 -0
  128. package/src/web/selectbox/selectbox.css +1 -0
  129. package/src/web/selectbox/selectbox.tsx +1048 -0
  130. package/src/web/sonner/AI_GUIDE.md +98 -0
  131. package/src/web/sonner/index.ts +114 -0
  132. package/src/web/sonner/manifest.json +132 -0
  133. package/src/web/sonner/sonner.css +1 -0
  134. package/src/web/sonner/sonner.tsx +177 -0
  135. package/src/web/table/AI_GUIDE.md +145 -0
  136. package/src/web/table/index.ts +35 -0
  137. package/src/web/table/manifest.json +168 -0
  138. package/src/web/table/table-body.tsx +45 -0
  139. package/src/web/table/table-caption.tsx +45 -0
  140. package/src/web/table/table-cell.tsx +74 -0
  141. package/src/web/table/table-empty.tsx +108 -0
  142. package/src/web/table/table-footer.tsx +45 -0
  143. package/src/web/table/table-head.tsx +80 -0
  144. package/src/web/table/table-header.tsx +45 -0
  145. package/src/web/table/table-row.tsx +69 -0
  146. package/src/web/table/table.css +1 -0
  147. package/src/web/table/table.tsx +305 -0
  148. package/src/web/tabs/AI_GUIDE.md +150 -0
  149. package/src/web/tabs/index.ts +3 -0
  150. package/src/web/tabs/manifest.json +315 -0
  151. package/src/web/tabs/tabs.css +1 -0
  152. package/src/web/tabs/tabs.tsx +332 -0
  153. package/src/web/text/AI_GUIDE.md +129 -0
  154. package/src/web/text/index.ts +3 -0
  155. package/src/web/text/manifest.json +195 -0
  156. package/src/web/text/text.css +1 -0
  157. package/src/web/text/text.tsx +689 -0
  158. package/src/web/textarea/AI_GUIDE.md +141 -0
  159. package/src/web/textarea/index.ts +3 -0
  160. package/src/web/textarea/manifest.json +438 -0
  161. package/src/web/textarea/textarea.css +1 -0
  162. package/src/web/textarea/textarea.tsx +467 -0
  163. package/src/web/tooltip/AI_GUIDE.md +110 -0
  164. package/src/web/tooltip/index.ts +3 -0
  165. package/src/web/tooltip/manifest.json +222 -0
  166. package/src/web/tooltip/tooltip.css +1 -0
  167. package/src/web/tooltip/tooltip.tsx +423 -0
  168. package/src/webview/bottomsheet/AI_GUIDE.md +141 -0
  169. package/src/webview/bottomsheet/bottomsheet.css +1 -0
  170. package/src/webview/bottomsheet/bottomsheet.tsx +603 -0
  171. package/src/webview/bottomsheet/index.ts +4 -0
  172. package/src/webview/bottomsheet/manifest.json +377 -0
  173. package/src/webview/button/AI_GUIDE.md +79 -0
  174. package/src/webview/button/button-ios.css +1 -0
  175. package/src/webview/button/button-ios.tsx +138 -0
  176. package/src/webview/button/button-material.css +1 -0
  177. package/src/webview/button/button-material.tsx +138 -0
  178. package/src/webview/button/index.ts +7 -0
  179. package/src/webview/button/manifest.json +148 -0
  180. package/src/webview/index.ts +7 -0
  181. package/tailwind-preset.cjs +62 -0
  182. package/tailwind-preset.js +62 -0
  183. package/ttdk-manifest.json +10188 -0
  184. package/README.md +0 -3
@@ -0,0 +1 @@
1
+ .ttdk-breadcrumb{box-sizing:border-box;font-family:var(--ttdk-font-sans);align-items:center;max-width:100%;line-height:1.5;display:flex}.ttdk-breadcrumb[data-size=sm]{font-size:var(--custom-text-size,12px)}.ttdk-breadcrumb[data-size=sm] .ttdk-breadcrumb-list,.ttdk-breadcrumb[data-size=sm] .ttdk-breadcrumb-item{gap:var(--custom-gap,6px)}.ttdk-breadcrumb[data-size=sm] .ttdk-separator-icon{width:12px;height:12px}.ttdk-breadcrumb[data-size=sm] .ttdk-breadcrumb-icon{font-size:13px}.ttdk-breadcrumb[data-size=md]{font-size:var(--custom-text-size,14px)}.ttdk-breadcrumb[data-size=md] .ttdk-breadcrumb-list,.ttdk-breadcrumb[data-size=md] .ttdk-breadcrumb-item{gap:var(--custom-gap,8px)}.ttdk-breadcrumb[data-size=md] .ttdk-separator-icon{width:14px;height:14px}.ttdk-breadcrumb[data-size=md] .ttdk-breadcrumb-icon{font-size:15px}.ttdk-breadcrumb[data-size=lg]{font-size:var(--custom-text-size,16px)}.ttdk-breadcrumb[data-size=lg] .ttdk-breadcrumb-list,.ttdk-breadcrumb[data-size=lg] .ttdk-breadcrumb-item{gap:var(--custom-gap,10px)}.ttdk-breadcrumb[data-size=lg] .ttdk-separator-icon{width:16px;height:16px}.ttdk-breadcrumb[data-size=lg] .ttdk-breadcrumb-icon{font-size:17px}.ttdk-breadcrumb[data-size=lg] .ttdk-breadcrumb-ellipsis{height:24px;padding:0 8px;font-size:15px}.ttdk-breadcrumb-list{flex-wrap:wrap;align-items:center;margin:0;padding:0;list-style:none;display:flex}.ttdk-breadcrumb-item{align-items:center;display:inline-flex}.ttdk-breadcrumb-link{color:var(--custom-link-color,var(--ttdk-ui-color,var(--ttdk-text-icon-secondary)));cursor:pointer;font-family:inherit;font-weight:400;font-size:inherit;line-height:inherit;background:0 0;border:none;align-items:center;gap:4px;padding:0;text-decoration:none;transition:color .15s,opacity .15s;display:inline-flex}.ttdk-breadcrumb-link:hover:not(:disabled){color:var(--ttdk-text-icon-primary);text-underline-offset:2px;text-decoration:underline}.ttdk-breadcrumb-link:focus-visible{box-shadow:0 0 0 2px var(--ttdk-stroke-border-focus);border-radius:2px;outline:none}.ttdk-breadcrumb-link:disabled,.ttdk-breadcrumb-link[data-disabled=true]{opacity:.45;cursor:not-allowed;pointer-events:none}.ttdk-breadcrumb-btn{user-select:none}.ttdk-breadcrumb-current{color:var(--custom-current-color,var(--ttdk-ui-color,var(--ttdk-text-icon-primary)));user-select:text;align-items:center;gap:4px;font-weight:600;display:inline-flex}.ttdk-breadcrumb-current[data-disabled=true]{opacity:.45}.ttdk-breadcrumb-separator{color:var(--ttdk-stroke-divider);user-select:none;justify-content:center;align-items:center;font-weight:400;display:inline-flex}.ttdk-separator-char{line-height:1}.ttdk-separator-icon{fill:currentColor;display:block;transform:rotate(270deg)}.ttdk-breadcrumb-label{vertical-align:middle;display:inline-block}.ttdk-breadcrumb-ellipsis{color:var(--ttdk-text-icon-primary);letter-spacing:1.5px;user-select:none;justify-content:center;align-items:center;font-weight:600;line-height:1;display:inline-flex}.ttdk-breadcrumb-slot{margin-left:12px}.dark .ttdk-breadcrumb-link,html.dark .ttdk-breadcrumb-link,[data-mode=dark] .ttdk-breadcrumb-link,[data-theme=dark] .ttdk-breadcrumb-link{color:var(--ttdk-text-icon-secondary)}.dark .ttdk-breadcrumb-link:hover:not(:disabled),html.dark .ttdk-breadcrumb-link:hover:not(:disabled),[data-mode=dark] .ttdk-breadcrumb-link:hover:not(:disabled),[data-theme=dark] .ttdk-breadcrumb-link:hover:not(:disabled),.dark .ttdk-breadcrumb-current,html.dark .ttdk-breadcrumb-current,[data-mode=dark] .ttdk-breadcrumb-current,[data-theme=dark] .ttdk-breadcrumb-current{color:var(--ttdk-text-icon-primary)}.dark .ttdk-breadcrumb-separator,html.dark .ttdk-breadcrumb-separator,[data-mode=dark] .ttdk-breadcrumb-separator,[data-theme=dark] .ttdk-breadcrumb-separator{color:var(--ttdk-stroke-divider)}.dark .ttdk-breadcrumb-ellipsis,html.dark .ttdk-breadcrumb-ellipsis,[data-mode=dark] .ttdk-breadcrumb-ellipsis,[data-theme=dark] .ttdk-breadcrumb-ellipsis{color:var(--ttdk-text-icon-primary)}
@@ -0,0 +1,306 @@
1
+ "use client";
2
+ import * as React from "react";
3
+
4
+ export interface BreadcrumbItem {
5
+ /**
6
+ * Label teks yang ditampilkan pada breadcrumb item.
7
+ */
8
+ label: string;
9
+
10
+ /**
11
+ * URL tautan navigasi tujuan (href / path).
12
+ */
13
+ href?: string;
14
+
15
+ /**
16
+ * Ikon atau emoji opsional di samping label teks.
17
+ */
18
+ icon?: any;
19
+
20
+ /**
21
+ * Menandai item ini secara eksplisit sebagai halaman saat ini (current page).
22
+ */
23
+ current?: boolean;
24
+
25
+ /**
26
+ * Menonaktifkan interaksi klik pada item ini.
27
+ * @default false
28
+ */
29
+ disabled?: boolean;
30
+
31
+ /**
32
+ * Menandai item sebagai representasi ellipsis penyingkat item yang tersembunyi.
33
+ */
34
+ isEllipsis?: boolean;
35
+ }
36
+ export type BreadcrumbUiProps = UiProps;
37
+ export type BreadcrumbSeparator = "chevron";
38
+ export interface BreadcrumbProps {
39
+ /**
40
+ * Daftar item navigasi breadcrumb dari tingkat teratas hingga halaman saat ini.
41
+ */
42
+ items: BreadcrumbItem[];
43
+
44
+ /**
45
+ * Jenis karakter atau ikon pemisah antar item:
46
+ * - `'arrow'`: Ikon panah kanan `→`.
47
+ *
48
+ * @default 'arrow'
49
+ */
50
+ separator?: BreadcrumbSeparator;
51
+
52
+ /**
53
+ * Karakter atau string teks khusus untuk pemisah antarelemen.
54
+ */
55
+ customSeparator?: string;
56
+
57
+ /**
58
+ * Skala ukuran tampilan breadcrumb:
59
+ * - `'sm'`: Kompak (12px, gap 6px).
60
+ * - `'md'`: Standar (14px, gap 8px).
61
+ * - `'lg'`: Besar (16px, gap 12px).
62
+ *
63
+ * @default 'md'
64
+ */
65
+ size?: "sm" | "md" | "lg";
66
+
67
+ /**
68
+ * Batas maksimum panjang karakter label sebelum dipotong (truncate).
69
+ * @default 20
70
+ */
71
+ maxLabelLength?: number;
72
+
73
+ /**
74
+ * Kustomisasi visual granular melalui style-like object (+ support pseudo-class: hover, active).
75
+ */
76
+ ui?: UiProps;
77
+
78
+ /**
79
+ * Inline CSS style object native.
80
+ */
81
+ style?: React.CSSProperties;
82
+
83
+ /**
84
+ * Style kustom untuk teks tautan breadcrumb / item non-aktif (UiProps).
85
+ */
86
+ textLinkStyle?: UiProps;
87
+
88
+ /**
89
+ * Class CSS kustom untuk teks tautan breadcrumb / item non-aktif (Tailwind / class kustom).
90
+ */
91
+ textLinkClass?: string;
92
+
93
+ /**
94
+ * Style kustom untuk teks item aktif / halaman saat ini (UiProps).
95
+ */
96
+ textActiveStyle?: UiProps;
97
+
98
+ /**
99
+ * Class CSS kustom untuk teks item aktif / halaman saat ini (Tailwind / class kustom).
100
+ */
101
+ textActiveClass?: string;
102
+
103
+ /**
104
+ * Style kustom untuk karakter atau ikon pemisah (UiProps).
105
+ */
106
+ separatorStyle?: UiProps;
107
+
108
+ /**
109
+ * Class CSS kustom untuk karakter atau ikon pemisah (Tailwind / class kustom).
110
+ */
111
+ separatorClass?: string;
112
+
113
+ /**
114
+ * Handler event klik yang dipanggil saat suatu item breadcrumb diklik.
115
+ *
116
+ * @param item Data item yang diklik.
117
+ * @param index Indeks urutan item dalam array.
118
+ * @param event Objek synthetic DOM event.
119
+ */
120
+ onItemClick?: (item: BreadcrumbItem, index: number, event: any) => void;
121
+
122
+ /**
123
+ * Class CSS kustom.
124
+ */
125
+ className?: string;
126
+
127
+ /**
128
+ * Slot konten tambahan di ujung kanan breadcrumb.
129
+ */
130
+ children?: any;
131
+ }
132
+
133
+ /**
134
+ * Komponen Breadcrumb untuk menampilkan hierarki navigasi lokasi halaman saat ini dengan dukungan penyingkatan (collapse ellipsis).
135
+ */
136
+
137
+ import { buildUiVars, UiProps } from "../../core/types";
138
+
139
+ function Breadcrumb(props: BreadcrumbProps) {
140
+ function formatLabel(label: any) {
141
+ if (!label && label !== 0) return "";
142
+ const str = String(label);
143
+ const max = props.maxLabelLength !== undefined ? props.maxLabelLength : 20;
144
+ if (max > 0 && str.length > max) {
145
+ return `${str.slice(0, max)}...`;
146
+ }
147
+ return str;
148
+ }
149
+
150
+ function getVisibleItems() {
151
+ if (!props.items || props.items.length === 0) return [];
152
+ const total = props.items.length;
153
+ if (total <= 3) {
154
+ return props.items;
155
+ }
156
+ const before = Math.max(1, Math.min(3, total - 2));
157
+ const startItems = props.items.slice(0, before);
158
+ const endItems = props.items.slice(total - 1);
159
+ const ellipsisItem: BreadcrumbItem = {
160
+ label: "...",
161
+ isEllipsis: true,
162
+ };
163
+ return [...startItems, ellipsisItem, ...endItems];
164
+ }
165
+
166
+ return (
167
+ <nav
168
+ aria-label="Breadcrumb"
169
+ className={`ttdk-breadcrumb ${props.className || ""}`.trim()}
170
+ data-size={props.size || "md"}
171
+ style={{
172
+ ...buildUiVars(props.ui),
173
+ ...((props as any)["style"] || {}),
174
+ ...props.style,
175
+ }}
176
+ >
177
+ <ol className="ttdk-breadcrumb-list">
178
+ {getVisibleItems()?.map((item, index) => (
179
+ <li className="ttdk-breadcrumb-item" key={index}>
180
+ {item.isEllipsis ? (
181
+ <span className="ttdk-breadcrumb-ellipsis" aria-hidden="true">
182
+ ···
183
+ </span>
184
+ ) : null}
185
+ {!item.isEllipsis &&
186
+ (item.current || index === getVisibleItems().length - 1) ? (
187
+ <span
188
+ aria-current="page"
189
+ className={`ttdk-breadcrumb-current ${
190
+ props.textActiveClass || ""
191
+ }`.trim()}
192
+ data-disabled={item.disabled ? "true" : "false"}
193
+ style={{
194
+ ...buildUiVars(props.textActiveStyle),
195
+ }}
196
+ >
197
+ {item.icon ? (
198
+ <span className="ttdk-breadcrumb-icon">{item.icon}</span>
199
+ ) : null}
200
+ <span className="ttdk-breadcrumb-label" title={item.label}>
201
+ {formatLabel(item.label)}
202
+ </span>
203
+ </span>
204
+ ) : null}
205
+ {!item.isEllipsis &&
206
+ !item.current &&
207
+ index !== getVisibleItems().length - 1 ? (
208
+ <>
209
+ {item.href ? (
210
+ <a
211
+ href={item.href}
212
+ className={`ttdk-breadcrumb-link ${
213
+ props.textLinkClass || ""
214
+ }`.trim()}
215
+ data-disabled={item.disabled ? "true" : "false"}
216
+ title={item.label}
217
+ style={{
218
+ ...buildUiVars(props.textLinkStyle),
219
+ }}
220
+ onClick={(e) => {
221
+ if (item.disabled) {
222
+ e.preventDefault();
223
+ return;
224
+ }
225
+ if (props.onItemClick) {
226
+ props.onItemClick(item, index, e);
227
+ }
228
+ }}
229
+ >
230
+ {item.icon ? (
231
+ <span className="ttdk-breadcrumb-icon">{item.icon}</span>
232
+ ) : null}
233
+ <span className="ttdk-breadcrumb-label">
234
+ {formatLabel(item.label)}
235
+ </span>
236
+ </a>
237
+ ) : null}
238
+ {!item.href ? (
239
+ <button
240
+ type="button"
241
+ className={`ttdk-breadcrumb-link ttdk-breadcrumb-btn ${
242
+ props.textLinkClass || ""
243
+ }`.trim()}
244
+ data-disabled={item.disabled ? "true" : "false"}
245
+ disabled={item.disabled}
246
+ title={item.label}
247
+ style={{
248
+ ...buildUiVars(props.textLinkStyle),
249
+ }}
250
+ onClick={(e) => {
251
+ if (props.onItemClick) {
252
+ props.onItemClick(item, index, e);
253
+ }
254
+ }}
255
+ >
256
+ {item.icon ? (
257
+ <span className="ttdk-breadcrumb-icon">{item.icon}</span>
258
+ ) : null}
259
+ <span className="ttdk-breadcrumb-label">
260
+ {formatLabel(item.label)}
261
+ </span>
262
+ </button>
263
+ ) : null}
264
+ </>
265
+ ) : null}
266
+ {index !== getVisibleItems().length - 1 ? (
267
+ <span
268
+ aria-hidden="true"
269
+ className={`ttdk-breadcrumb-separator ${
270
+ props.separatorClass || ""
271
+ }`.trim()}
272
+ style={{
273
+ ...buildUiVars(props.separatorStyle),
274
+ }}
275
+ >
276
+ {props.customSeparator ? (
277
+ <span className="ttdk-separator-char">
278
+ {props.customSeparator}
279
+ </span>
280
+ ) : null}
281
+ {!props.customSeparator ? (
282
+ <svg
283
+ className="ttdk-separator-icon"
284
+ xmlns="http://www.w3.org/2000/svg"
285
+ viewBox="0 0 640 640"
286
+ >
287
+ <path d="M297.4 470.6C309.9 483.1 330.2 483.1 342.7 470.6L534.7 278.6C547.2 266.1 547.2 245.8 534.7 233.3C522.2 220.8 501.9 220.8 489.4 233.3L320 402.7L150.6 233.4C138.1 220.9 117.8 220.9 105.3 233.4C92.8 245.9 92.8 266.2 105.3 278.7L297.3 470.7z" />
288
+ </svg>
289
+ ) : null}
290
+ </span>
291
+ ) : null}
292
+ </li>
293
+ ))}
294
+ </ol>
295
+ {props.children ? (
296
+ <div className="ttdk-breadcrumb-slot">
297
+ <>{props.children}</>
298
+ </div>
299
+ ) : null}
300
+ </nav>
301
+ );
302
+ }
303
+
304
+ export default Breadcrumb;
305
+
306
+ export { Breadcrumb };
@@ -0,0 +1,3 @@
1
+ export { default as Breadcrumb } from './breadcrumb';
2
+ export { default } from './breadcrumb';
3
+ export * from './breadcrumb'
@@ -0,0 +1,225 @@
1
+ {
2
+ "name": "@ttdk-design-system/breadcrumb",
3
+ "component": "Breadcrumb",
4
+ "folder": "breadcrumb",
5
+ "description": "Komponen Breadcrumb untuk menampilkan hierarki navigasi lokasi halaman saat ini dengan dukungan penyingkatan (collapse ellipsis).",
6
+ "stylesheets": [
7
+ {
8
+ "theme": "common",
9
+ "file": "breadcrumb.css",
10
+ "importPath": "web/breadcrumb/breadcrumb.css"
11
+ }
12
+ ],
13
+ "props": {
14
+ "items": {
15
+ "name": "items",
16
+ "type": "BreadcrumbItem[]",
17
+ "optional": false,
18
+ "default": null,
19
+ "description": "Daftar item navigasi breadcrumb dari tingkat teratas hingga halaman saat ini.",
20
+ "example": null,
21
+ "param": null
22
+ },
23
+ "separator": {
24
+ "name": "separator",
25
+ "type": "BreadcrumbSeparator",
26
+ "optional": true,
27
+ "default": "arrow",
28
+ "description": "Jenis karakter atau ikon pemisah antar item: - `'arrow'`: Ikon panah kanan `→`.",
29
+ "example": null,
30
+ "param": null
31
+ },
32
+ "customSeparator": {
33
+ "name": "customSeparator",
34
+ "type": "string",
35
+ "optional": true,
36
+ "default": null,
37
+ "description": "Karakter atau string teks khusus untuk pemisah antarelemen.",
38
+ "example": null,
39
+ "param": null
40
+ },
41
+ "size": {
42
+ "name": "size",
43
+ "type": "'sm' | 'md' | 'lg'",
44
+ "optional": true,
45
+ "default": "md",
46
+ "description": "Skala ukuran tampilan breadcrumb: - `'sm'`: Kompak (12px, gap 6px). - `'md'`: Standar (14px, gap 8px). - `'lg'`: Besar (16px, gap 12px).",
47
+ "example": null,
48
+ "param": null
49
+ },
50
+ "maxLabelLength": {
51
+ "name": "maxLabelLength",
52
+ "type": "number",
53
+ "optional": true,
54
+ "default": "20",
55
+ "description": "Batas maksimum panjang karakter label sebelum dipotong (truncate).",
56
+ "example": null,
57
+ "param": null
58
+ },
59
+ "ui": {
60
+ "name": "ui",
61
+ "type": "UiProps",
62
+ "optional": true,
63
+ "default": null,
64
+ "description": "Kustomisasi visual granular melalui style-like object (+ support pseudo-class: hover, active).",
65
+ "example": null,
66
+ "param": null
67
+ },
68
+ "style": {
69
+ "name": "style",
70
+ "type": "any",
71
+ "optional": true,
72
+ "default": null,
73
+ "description": "Inline CSS style object native.",
74
+ "example": null,
75
+ "param": null
76
+ },
77
+ "textLinkStyle": {
78
+ "name": "textLinkStyle",
79
+ "type": "UiProps",
80
+ "optional": true,
81
+ "default": null,
82
+ "description": "Style kustom untuk teks tautan breadcrumb / item non-aktif (UiProps).",
83
+ "example": null,
84
+ "param": null
85
+ },
86
+ "textLinkClass": {
87
+ "name": "textLinkClass",
88
+ "type": "string",
89
+ "optional": true,
90
+ "default": null,
91
+ "description": "Class CSS kustom untuk teks tautan breadcrumb / item non-aktif (Tailwind / class kustom).",
92
+ "example": null,
93
+ "param": null
94
+ },
95
+ "textActiveStyle": {
96
+ "name": "textActiveStyle",
97
+ "type": "UiProps",
98
+ "optional": true,
99
+ "default": null,
100
+ "description": "Style kustom untuk teks item aktif / halaman saat ini (UiProps).",
101
+ "example": null,
102
+ "param": null
103
+ },
104
+ "textActiveClass": {
105
+ "name": "textActiveClass",
106
+ "type": "string",
107
+ "optional": true,
108
+ "default": null,
109
+ "description": "Class CSS kustom untuk teks item aktif / halaman saat ini (Tailwind / class kustom).",
110
+ "example": null,
111
+ "param": null
112
+ },
113
+ "separatorStyle": {
114
+ "name": "separatorStyle",
115
+ "type": "UiProps",
116
+ "optional": true,
117
+ "default": null,
118
+ "description": "Style kustom untuk karakter atau ikon pemisah (UiProps).",
119
+ "example": null,
120
+ "param": null
121
+ },
122
+ "separatorClass": {
123
+ "name": "separatorClass",
124
+ "type": "string",
125
+ "optional": true,
126
+ "default": null,
127
+ "description": "Class CSS kustom untuk karakter atau ikon pemisah (Tailwind / class kustom).",
128
+ "example": null,
129
+ "param": null
130
+ },
131
+ "onItemClick": {
132
+ "name": "onItemClick",
133
+ "type": "(item: BreadcrumbItem, index: number, event: any) => void",
134
+ "optional": true,
135
+ "default": null,
136
+ "description": "Handler event klik yang dipanggil saat suatu item breadcrumb diklik.",
137
+ "example": null,
138
+ "param": "event Objek synthetic DOM event."
139
+ },
140
+ "className": {
141
+ "name": "className",
142
+ "type": "string",
143
+ "optional": true,
144
+ "default": null,
145
+ "description": "Class CSS kustom.",
146
+ "example": null,
147
+ "param": null
148
+ },
149
+ "children": {
150
+ "name": "children",
151
+ "type": "any",
152
+ "optional": true,
153
+ "default": null,
154
+ "description": "Slot konten tambahan di ujung kanan breadcrumb.",
155
+ "example": null,
156
+ "param": null
157
+ }
158
+ },
159
+ "subInterfaces": {
160
+ "BreadcrumbItem": {
161
+ "label": {
162
+ "name": "label",
163
+ "type": "string",
164
+ "optional": false,
165
+ "default": null,
166
+ "description": "Label teks yang ditampilkan pada breadcrumb item.",
167
+ "example": null,
168
+ "param": null
169
+ },
170
+ "href": {
171
+ "name": "href",
172
+ "type": "string",
173
+ "optional": true,
174
+ "default": null,
175
+ "description": "URL tautan navigasi tujuan (href / path).",
176
+ "example": null,
177
+ "param": null
178
+ },
179
+ "icon": {
180
+ "name": "icon",
181
+ "type": "any",
182
+ "optional": true,
183
+ "default": null,
184
+ "description": "Ikon atau emoji opsional di samping label teks.",
185
+ "example": null,
186
+ "param": null
187
+ },
188
+ "current": {
189
+ "name": "current",
190
+ "type": "boolean",
191
+ "optional": true,
192
+ "default": null,
193
+ "description": "Menandai item ini secara eksplisit sebagai halaman saat ini (current page).",
194
+ "example": null,
195
+ "param": null
196
+ },
197
+ "disabled": {
198
+ "name": "disabled",
199
+ "type": "boolean",
200
+ "optional": true,
201
+ "default": "false",
202
+ "description": "Menonaktifkan interaksi klik pada item ini.",
203
+ "example": null,
204
+ "param": null
205
+ },
206
+ "isEllipsis": {
207
+ "name": "isEllipsis",
208
+ "type": "boolean",
209
+ "optional": true,
210
+ "default": null,
211
+ "description": "Menandai item sebagai representasi ellipsis penyingkat item yang tersembunyi.",
212
+ "example": null,
213
+ "param": null
214
+ }
215
+ }
216
+ },
217
+ "supportedFrameworks": [
218
+ "react",
219
+ "vue",
220
+ "svelte"
221
+ ],
222
+ "themes": [
223
+ "tw"
224
+ ]
225
+ }
@@ -0,0 +1,121 @@
1
+ # <Button /> — TTDK Component Reference
2
+
3
+ TTDK Button component with multi-theme support.
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/button/button.css";`
8
+
9
+ ## 2. Subpath Component Import
10
+ ```ts
11
+ // React
12
+ import Button from "@ttdk-design-system/library-react/web/button";
13
+
14
+ // Vue 3
15
+ import Button from "@ttdk-design-system/library-vue/web/button";
16
+
17
+ // Svelte
18
+ import Button from "@ttdk-design-system/library-svelte/web/button";
19
+ ```
20
+
21
+ ## 3. Props & API Reference
22
+
23
+ | Prop | Type | Default | Description |
24
+ | :--- | :--- | :--- | :--- |
25
+ | `style?` | `any` | `-` | Inline CSS style kustom. |
26
+ | `variant?` | `| 'primary'
27
+ | 'info'
28
+ | 'warning'
29
+ | 'danger'
30
+ | 'neutral'
31
+ | 'disabled'` | `primary` | Varian warna semantik tombol: - `'primary'`: Teal utama. - `'info'`: Biru informasi. - `'warning'`: Kuning peringatan. - `'danger'`: Merah bahaya. - `'neutral'`: Abu-abu netral. - `'disabled'`: Tombol non-aktif. |
32
+ | `appearance?` | `'solid' | 'soft' | 'outline' | 'link' | 'ghost'` | `solid` | Gaya tampilan visual tombol: - `'solid'`: Latar belakang warna solid pekat (default). - `'soft'`: Latar belakang warna transparan lembut. - `'outline'`: Garis tepi dengan latar belakang transparan. - `'link'`: Teks tautan tanpa border/latar, dengan garis bawah saat hover. - `'ghost'`: Transparan tanpa outline/border, dengan latar lembut saat hover. |
33
+ | `type?` | `'button' | 'submit' | 'reset'` | `button` | Tipe tombol HTML native. |
34
+ | `size?` | `'sm' | 'md' | 'lg'` | `md` | Skala ukuran tombol: - `'sm'`: 36px - `'md'`: 48px (standar) - `'lg'`: 56px |
35
+ | `negative?` | `boolean` | `false` | Mode negatif — kontras tinggi di atas latar gelap. |
36
+ | `rounded?` | `'none' | 'sm' | 'md' | 'lg' | 'full'` | `md` | Radius sudut tombol. - `'none'`: 0px - `'sm'`: 4px - `'md'`: 8px (standar) - `'lg'`: 12px - `'full'`: 9999px (pill) |
37
+ | `iconOnly?` | `boolean` | `false` | Mode tombol ikon persegi (aspek rasio 1:1). |
38
+ | `block?` | `boolean` | `false` | Full-width — melebar 100% dari container. |
39
+ | `loading?` | `boolean` | `false` | Tampilkan spinner & nonaktifkan tombol saat proses async. |
40
+ | `disabled?` | `boolean` | `false` | Nonaktifkan tombol dari interaksi pengguna. |
41
+ | `iconColor?` | `string` | `-` | Warna kustom untuk ikon di dalam tombol (misal: '#fff', '#0968F6'). |
42
+ | `iconSize?` | `string` | `-` | Ukuran kustom untuk ikon di dalam tombol (misal: '16px', '20px'). |
43
+ | `ui?` | `UiProps` | `-` | Kustomisasi visual — seperti style object tapi dengan support pseudo-class. ```tsx <Button ui={{ background: '#7c3aed', color: 'white', borderRadius: '99px', hover: { background: '#6d28d9', transform: 'scale(1.02)', }, active: { opacity: '0.9', } }} /> ``` |
44
+ | `onClick?` | `(event?: any) => void` | `-` | Event handler saat tombol diklik. |
45
+ | `className?` | `string` | `-` | Class CSS kustom. |
46
+ | `children?` | `any` | `-` | Konten tombol — teks, ikon, atau JSX. |
47
+
48
+ ## 4. Usage Examples
49
+
50
+ ### React Example
51
+ ```tsx
52
+ import Button from "@ttdk-design-system/library-react/web/button";
53
+ import "@ttdk-design-system/library-react/web/button/button.css";
54
+
55
+ export function Example() {
56
+ return (
57
+ <div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
58
+ <Button variant="primary" onClick={() => alert("Simpan data")}>
59
+ Simpan
60
+ </Button>
61
+ <Button variant="secondary">
62
+ Batal
63
+ </Button>
64
+ <Button variant="outline">
65
+ Ekspor CSV
66
+ </Button>
67
+ <Button variant="danger">
68
+ Hapus
69
+ </Button>
70
+ </div>
71
+ );
72
+ }
73
+ ```
74
+
75
+ ### Vue 3 Example
76
+ ```vue
77
+ <script setup lang="ts">
78
+ import Button from "@ttdk-design-system/library-vue/web/button";
79
+ import "@ttdk-design-system/library-vue/web/button/button.css";
80
+ </script>
81
+
82
+ <template>
83
+ <div style="display: flex; gap: 10px; align-items: center;">
84
+ <Button variant="primary" @click="() => alert('Simpan data')">
85
+ Simpan
86
+ </Button>
87
+ <Button variant="secondary">
88
+ Batal
89
+ </Button>
90
+ <Button variant="outline">
91
+ Ekspor CSV
92
+ </Button>
93
+ <Button variant="danger">
94
+ Hapus
95
+ </Button>
96
+ </div>
97
+ </template>
98
+ ```
99
+
100
+ ### Svelte Example
101
+ ```svelte
102
+ <script lang="ts">
103
+ import Button from "@ttdk-design-system/library-svelte/web/button";
104
+ import "@ttdk-design-system/library-svelte/web/button/button.css";
105
+ </script>
106
+
107
+ <div style="display: flex; gap: 10px; align-items: center;">
108
+ <Button variant="primary" on:click={() => alert('Simpan data')}>
109
+ Simpan
110
+ </Button>
111
+ <Button variant="secondary">
112
+ Batal
113
+ </Button>
114
+ <Button variant="outline">
115
+ Ekspor CSV
116
+ </Button>
117
+ <Button variant="danger">
118
+ Hapus
119
+ </Button>
120
+ </div>
121
+ ```