@ttdk-design-system/library-vue 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 (232) hide show
  1. package/AI_GUIDE.md +6518 -0
  2. package/README.md +104 -2
  3. package/llms.txt +6518 -0
  4. package/package.json +1097 -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.vue +432 -0
  17. package/src/web/accordion/accordion.vue.d.ts +227 -0
  18. package/src/web/accordion/index.ts +3 -0
  19. package/src/web/accordion/manifest.json +351 -0
  20. package/src/web/alert/AI_GUIDE.md +139 -0
  21. package/src/web/alert/alert.css +1 -0
  22. package/src/web/alert/alert.vue +290 -0
  23. package/src/web/alert/alert.vue.d.ts +154 -0
  24. package/src/web/alert/index.ts +3 -0
  25. package/src/web/alert/manifest.json +240 -0
  26. package/src/web/avatar/AI_GUIDE.md +118 -0
  27. package/src/web/avatar/avatar.css +1 -0
  28. package/src/web/avatar/avatar.vue +217 -0
  29. package/src/web/avatar/avatar.vue.d.ts +135 -0
  30. package/src/web/avatar/index.ts +3 -0
  31. package/src/web/avatar/manifest.json +195 -0
  32. package/src/web/badge/AI_GUIDE.md +94 -0
  33. package/src/web/badge/badge.css +1 -0
  34. package/src/web/badge/badge.vue +135 -0
  35. package/src/web/badge/badge.vue.d.ts +108 -0
  36. package/src/web/badge/index.ts +3 -0
  37. package/src/web/badge/manifest.json +141 -0
  38. package/src/web/banner/AI_GUIDE.md +130 -0
  39. package/src/web/banner/banner.css +1 -0
  40. package/src/web/banner/banner.vue +303 -0
  41. package/src/web/banner/banner.vue.d.ts +162 -0
  42. package/src/web/banner/index.ts +3 -0
  43. package/src/web/banner/manifest.json +240 -0
  44. package/src/web/breadcrumb/AI_GUIDE.md +120 -0
  45. package/src/web/breadcrumb/breadcrumb.css +1 -0
  46. package/src/web/breadcrumb/breadcrumb.vue +313 -0
  47. package/src/web/breadcrumb/breadcrumb.vue.d.ts +139 -0
  48. package/src/web/breadcrumb/index.ts +3 -0
  49. package/src/web/breadcrumb/manifest.json +225 -0
  50. package/src/web/button/AI_GUIDE.md +121 -0
  51. package/src/web/button/button.css +1 -0
  52. package/src/web/button/button.vue +283 -0
  53. package/src/web/button/button.vue.d.ts +147 -0
  54. package/src/web/button/index.ts +3 -0
  55. package/src/web/button/manifest.json +177 -0
  56. package/src/web/calendar/AI_GUIDE.md +151 -0
  57. package/src/web/calendar/calendar.css +1 -0
  58. package/src/web/calendar/calendar.vue +1536 -0
  59. package/src/web/calendar/calendar.vue.d.ts +261 -0
  60. package/src/web/calendar/index.ts +3 -0
  61. package/src/web/calendar/manifest.json +470 -0
  62. package/src/web/card/AI_GUIDE.md +133 -0
  63. package/src/web/card/card.css +1 -0
  64. package/src/web/card/card.vue +423 -0
  65. package/src/web/card/card.vue.d.ts +232 -0
  66. package/src/web/card/index.ts +3 -0
  67. package/src/web/card/manifest.json +357 -0
  68. package/src/web/checkbox/AI_GUIDE.md +146 -0
  69. package/src/web/checkbox/checkbox.css +1 -0
  70. package/src/web/checkbox/checkbox.vue +304 -0
  71. package/src/web/checkbox/checkbox.vue.d.ts +189 -0
  72. package/src/web/checkbox/index.ts +3 -0
  73. package/src/web/checkbox/manifest.json +294 -0
  74. package/src/web/chip/AI_GUIDE.md +186 -0
  75. package/src/web/chip/chip.css +1 -0
  76. package/src/web/chip/chip.vue +220 -0
  77. package/src/web/chip/chip.vue.d.ts +140 -0
  78. package/src/web/chip/index.ts +3 -0
  79. package/src/web/chip/manifest.json +186 -0
  80. package/src/web/dropdown/AI_GUIDE.md +167 -0
  81. package/src/web/dropdown/dropdown.css +1 -0
  82. package/src/web/dropdown/dropdown.vue +1257 -0
  83. package/src/web/dropdown/dropdown.vue.d.ts +381 -0
  84. package/src/web/dropdown/index.ts +3 -0
  85. package/src/web/dropdown/manifest.json +576 -0
  86. package/src/web/flex/AI_GUIDE.md +113 -0
  87. package/src/web/flex/flex-item.vue +94 -0
  88. package/src/web/flex/flex-item.vue.d.ts +84 -0
  89. package/src/web/flex/flex.css +1 -0
  90. package/src/web/flex/flex.vue +103 -0
  91. package/src/web/flex/flex.vue.d.ts +92 -0
  92. package/src/web/flex/index.ts +5 -0
  93. package/src/web/flex/manifest.json +162 -0
  94. package/src/web/form/index.ts +7 -0
  95. package/src/web/grid/AI_GUIDE.md +112 -0
  96. package/src/web/grid/grid-item.vue +109 -0
  97. package/src/web/grid/grid-item.vue.d.ts +99 -0
  98. package/src/web/grid/grid.css +1 -0
  99. package/src/web/grid/grid.vue +94 -0
  100. package/src/web/grid/grid.vue.d.ts +84 -0
  101. package/src/web/grid/index.ts +5 -0
  102. package/src/web/grid/manifest.json +153 -0
  103. package/src/web/index.ts +86 -0
  104. package/src/web/input/AI_GUIDE.md +159 -0
  105. package/src/web/input/index.ts +3 -0
  106. package/src/web/input/input.css +1 -0
  107. package/src/web/input/input.vue +521 -0
  108. package/src/web/input/input.vue.d.ts +274 -0
  109. package/src/web/input/manifest.json +465 -0
  110. package/src/web/input-number/AI_GUIDE.md +164 -0
  111. package/src/web/input-number/index.ts +3 -0
  112. package/src/web/input-number/input-number.css +1 -0
  113. package/src/web/input-number/input-number.vue +1153 -0
  114. package/src/web/input-number/input-number.vue.d.ts +343 -0
  115. package/src/web/input-number/manifest.json +575 -0
  116. package/src/web/modal/AI_GUIDE.md +171 -0
  117. package/src/web/modal/index.ts +3 -0
  118. package/src/web/modal/manifest.json +375 -0
  119. package/src/web/modal/modal.css +1 -0
  120. package/src/web/modal/modal.vue +344 -0
  121. package/src/web/modal/modal.vue.d.ts +64 -0
  122. package/src/web/pagination/AI_GUIDE.md +148 -0
  123. package/src/web/pagination/index.ts +21 -0
  124. package/src/web/pagination/manifest.json +432 -0
  125. package/src/web/pagination/pagination-content.vue +42 -0
  126. package/src/web/pagination/pagination-content.vue.d.ts +28 -0
  127. package/src/web/pagination/pagination-ellipsis.vue +55 -0
  128. package/src/web/pagination/pagination-ellipsis.vue.d.ts +28 -0
  129. package/src/web/pagination/pagination-first.vue +161 -0
  130. package/src/web/pagination/pagination-first.vue.d.ts +67 -0
  131. package/src/web/pagination/pagination-item.vue +42 -0
  132. package/src/web/pagination/pagination-item.vue.d.ts +28 -0
  133. package/src/web/pagination/pagination-last.vue +161 -0
  134. package/src/web/pagination/pagination-last.vue.d.ts +67 -0
  135. package/src/web/pagination/pagination-link.vue +118 -0
  136. package/src/web/pagination/pagination-link.vue.d.ts +61 -0
  137. package/src/web/pagination/pagination-next.vue +160 -0
  138. package/src/web/pagination/pagination-next.vue.d.ts +68 -0
  139. package/src/web/pagination/pagination-previous.vue +160 -0
  140. package/src/web/pagination/pagination-previous.vue.d.ts +68 -0
  141. package/src/web/pagination/pagination.css +1 -0
  142. package/src/web/pagination/pagination.vue +730 -0
  143. package/src/web/pagination/pagination.vue.d.ts +247 -0
  144. package/src/web/popover/AI_GUIDE.md +163 -0
  145. package/src/web/popover/index.ts +3 -0
  146. package/src/web/popover/manifest.json +396 -0
  147. package/src/web/popover/popover.css +1 -0
  148. package/src/web/popover/popover.vue +579 -0
  149. package/src/web/popover/popover.vue.d.ts +83 -0
  150. package/src/web/radio/AI_GUIDE.md +155 -0
  151. package/src/web/radio/index.ts +3 -0
  152. package/src/web/radio/manifest.json +294 -0
  153. package/src/web/radio/radio.css +1 -0
  154. package/src/web/radio/radio.vue +288 -0
  155. package/src/web/radio/radio.vue.d.ts +182 -0
  156. package/src/web/selectbox/AI_GUIDE.md +216 -0
  157. package/src/web/selectbox/index.ts +3 -0
  158. package/src/web/selectbox/manifest.json +477 -0
  159. package/src/web/selectbox/selectbox.css +1 -0
  160. package/src/web/selectbox/selectbox.vue +1024 -0
  161. package/src/web/selectbox/selectbox.vue.d.ts +300 -0
  162. package/src/web/sonner/AI_GUIDE.md +98 -0
  163. package/src/web/sonner/index.ts +114 -0
  164. package/src/web/sonner/manifest.json +132 -0
  165. package/src/web/sonner/sonner.css +1 -0
  166. package/src/web/sonner/sonner.vue +180 -0
  167. package/src/web/sonner/sonner.vue.d.ts +113 -0
  168. package/src/web/table/AI_GUIDE.md +145 -0
  169. package/src/web/table/index.ts +34 -0
  170. package/src/web/table/manifest.json +168 -0
  171. package/src/web/table/table-body.vue +42 -0
  172. package/src/web/table/table-body.vue.d.ts +28 -0
  173. package/src/web/table/table-caption.vue +42 -0
  174. package/src/web/table/table-caption.vue.d.ts +28 -0
  175. package/src/web/table/table-cell.vue +71 -0
  176. package/src/web/table/table-cell.vue.d.ts +49 -0
  177. package/src/web/table/table-empty.vue +105 -0
  178. package/src/web/table/table-empty.vue.d.ts +57 -0
  179. package/src/web/table/table-footer.vue +42 -0
  180. package/src/web/table/table-footer.vue.d.ts +28 -0
  181. package/src/web/table/table-head.vue +78 -0
  182. package/src/web/table/table-head.vue.d.ts +50 -0
  183. package/src/web/table/table-header.vue +42 -0
  184. package/src/web/table/table-header.vue.d.ts +28 -0
  185. package/src/web/table/table-row.vue +70 -0
  186. package/src/web/table/table-row.vue.d.ts +44 -0
  187. package/src/web/table/table.css +1 -0
  188. package/src/web/table/table.vue +298 -0
  189. package/src/web/table/table.vue.d.ts +119 -0
  190. package/src/web/tabs/AI_GUIDE.md +150 -0
  191. package/src/web/tabs/index.ts +2 -0
  192. package/src/web/tabs/manifest.json +315 -0
  193. package/src/web/tabs/tabs.css +1 -0
  194. package/src/web/tabs/tabs.vue +164 -0
  195. package/src/web/tabs/tabs.vue.d.ts +60 -0
  196. package/src/web/text/AI_GUIDE.md +129 -0
  197. package/src/web/text/index.ts +2 -0
  198. package/src/web/text/manifest.json +195 -0
  199. package/src/web/text/text.css +1 -0
  200. package/src/web/text/text.vue +195 -0
  201. package/src/web/text/text.vue.d.ts +161 -0
  202. package/src/web/textarea/AI_GUIDE.md +141 -0
  203. package/src/web/textarea/index.ts +3 -0
  204. package/src/web/textarea/manifest.json +438 -0
  205. package/src/web/textarea/textarea.css +1 -0
  206. package/src/web/textarea/textarea.vue +458 -0
  207. package/src/web/textarea/textarea.vue.d.ts +265 -0
  208. package/src/web/tooltip/AI_GUIDE.md +110 -0
  209. package/src/web/tooltip/index.ts +3 -0
  210. package/src/web/tooltip/manifest.json +222 -0
  211. package/src/web/tooltip/tooltip.css +1 -0
  212. package/src/web/tooltip/tooltip.vue +417 -0
  213. package/src/web/tooltip/tooltip.vue.d.ts +150 -0
  214. package/src/webview/bottomsheet/AI_GUIDE.md +141 -0
  215. package/src/webview/bottomsheet/bottomsheet.css +1 -0
  216. package/src/webview/bottomsheet/bottomsheet.vue +441 -0
  217. package/src/webview/bottomsheet/bottomsheet.vue.d.ts +178 -0
  218. package/src/webview/bottomsheet/index.ts +4 -0
  219. package/src/webview/bottomsheet/manifest.json +377 -0
  220. package/src/webview/button/AI_GUIDE.md +79 -0
  221. package/src/webview/button/button-ios.css +1 -0
  222. package/src/webview/button/button-ios.vue +138 -0
  223. package/src/webview/button/button-ios.vue.d.ts +102 -0
  224. package/src/webview/button/button-material.css +1 -0
  225. package/src/webview/button/button-material.vue +138 -0
  226. package/src/webview/button/button-material.vue.d.ts +102 -0
  227. package/src/webview/button/index.ts +7 -0
  228. package/src/webview/button/manifest.json +148 -0
  229. package/src/webview/index.ts +7 -0
  230. package/tailwind-preset.cjs +62 -0
  231. package/tailwind-preset.js +62 -0
  232. package/ttdk-manifest.json +10188 -0
@@ -0,0 +1,417 @@
1
+ <template>
2
+ <div
3
+ :class="`ttdk-tooltip-wrapper ${className || ''}`.trim()"
4
+ :data-open="isOpen ? 'true' : 'false'"
5
+ :data-disabled="disabled ? 'true' : 'false'"
6
+ :style="{
7
+ ...buildUiVars(ui),
8
+ ...(typeof style === 'object' ? style : {}),
9
+ }"
10
+ >
11
+ <div
12
+ ref="triggerRef"
13
+ :class="`ttdk-tooltip-trigger ${triggerClass || ''}`.trim()"
14
+ :tabIndex="disabled ? -1 : 0"
15
+ :aria-describedby="isOpen ? 'ttdk-tooltip' : undefined"
16
+ :data-open="isOpen ? 'true' : 'false'"
17
+ :data-disabled="disabled ? 'true' : 'false'"
18
+ :style="{
19
+ ...buildUiVars(triggerStyle),
20
+ }"
21
+ @pointerenter="async (event) => handlePointerEnter()"
22
+ @mouseenter="async (event) => handlePointerEnter()"
23
+ @pointerleave="async (event) => handlePointerLeave()"
24
+ @mouseleave="async (event) => handlePointerLeave()"
25
+ @focus="async (event) => handleFocus()"
26
+ @blur="async (event) => handleBlur()"
27
+ @keydown="async (e) => handleKeyDown(e)"
28
+ >
29
+ <template v-if="$slots.default">
30
+ <slot />
31
+ </template>
32
+ </div>
33
+ <template v-if="isOpen">
34
+ <div
35
+ role="tooltip"
36
+ ref="tooltipRef"
37
+ :class="`ttdk-tooltip-content ${contentClass || ''}`.trim()"
38
+ :style="{
39
+ ...buildUiVars(contentStyle),
40
+ }"
41
+ @pointerenter="async (event) => handlePointerEnter()"
42
+ @mouseenter="async (event) => handlePointerEnter()"
43
+ @pointerleave="async (event) => handlePointerLeave()"
44
+ @mouseleave="async (event) => handlePointerLeave()"
45
+ >
46
+ <template v-if="showArrow">
47
+ <div
48
+ ref="arrowRef"
49
+ :class="`ttdk-tooltip-arrow ${arrowClass || ''}`.trim()"
50
+ :style="{
51
+ ...buildUiVars(arrowStyle),
52
+ }"
53
+ ></div>
54
+ </template>
55
+
56
+ <div class="ttdk-tooltip-body">
57
+ <template v-if="text">
58
+ <span class="ttdk-tooltip-text">{{ text }}</span>
59
+ </template>
60
+
61
+ <template v-if="content && !text">
62
+ {{ content }}
63
+ </template>
64
+
65
+ <template v-if="!text && !content">
66
+ <slot name="content"></slot>
67
+ </template>
68
+
69
+ <template v-if="kbd">
70
+ <span class="ttdk-tooltip-kbd-list"
71
+ ><template :key="idx" v-for="(key, idx) in getKbdList()">
72
+ <kbd class="ttdk-tooltip-kbd">{{ key }}</kbd>
73
+ </template></span
74
+ >
75
+ </template>
76
+ </div>
77
+ </div>
78
+ </template>
79
+ </div>
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ import { onMounted, onUnmounted, ref, nextTick, watch, getCurrentInstance, computed } from "vue";
84
+
85
+ import {
86
+ computePosition,
87
+ autoUpdate,
88
+ flip,
89
+ shift,
90
+ offset,
91
+ arrow as floatingArrow,
92
+ } from "@floating-ui/dom";
93
+ import { buildUiVars, UiProps } from "../../core/types";
94
+
95
+ export type TooltipPlacement =
96
+ | "top"
97
+ | "top-start"
98
+ | "top-end"
99
+ | "bottom"
100
+ | "bottom-start"
101
+ | "bottom-end"
102
+ | "left"
103
+ | "left-start"
104
+ | "left-end"
105
+ | "right"
106
+ | "right-start"
107
+ | "right-end";
108
+ export type TooltipUiProps = UiProps;
109
+ export interface TooltipProps {
110
+ /**
111
+ * Teks konten tooltip yang ditampilkan.
112
+ */
113
+ text?: string;
114
+
115
+ /**
116
+ * Konten kustom tooltip (JSX / VNode atau renderable content).
117
+ */
118
+ content?: any;
119
+
120
+ /**
121
+ * Pintasan keyboard opsional yang ditampilkan di dalam tooltip (misal: '⌘K', ['Ctrl', 'S']).
122
+ */
123
+ kbd?: string | string[];
124
+
125
+ /**
126
+ * Posisi penempatan tooltip terhadap elemen pemicu.
127
+ * @default 'top'
128
+ */
129
+ placement?: TooltipPlacement;
130
+
131
+ /**
132
+ * Jarak offset dalam pixel dari elemen pemicu (trigger).
133
+ * @default 8
134
+ */
135
+ offsetDistance?: number;
136
+
137
+ /**
138
+ * Menampilkan elemen panah segitiga penunjuk arah ke elemen pemicu.
139
+ * @default true
140
+ */
141
+ arrow?: boolean;
142
+
143
+ /**
144
+ * Penundaan kemunculan tooltip dalam milidetik (delay saat pointer enter).
145
+ * @default 150
146
+ */
147
+ openDelay?: number;
148
+
149
+ /**
150
+ * Penundaan hilangnya tooltip dalam milidetik (delay saat pointer leave).
151
+ * @default 100
152
+ */
153
+ closeDelay?: number;
154
+
155
+ /**
156
+ * Status visibilitas tooltip terkontrol (controlled mode).
157
+ */
158
+ open?: boolean;
159
+
160
+ /**
161
+ * Status visibilitas awal (uncontrolled initial state).
162
+ * @default false
163
+ */
164
+ defaultOpen?: boolean;
165
+
166
+ /**
167
+ * Menonaktifkan tooltip sehingga tidak muncul saat di-hover atau difokus.
168
+ * @default false
169
+ */
170
+ disabled?: boolean;
171
+
172
+ /**
173
+ * Kustomisasi visual granular container utama (UiProps).
174
+ */
175
+ ui?: TooltipUiProps;
176
+
177
+ /**
178
+ * Style inline CSS native untuk wrapper luar.
179
+ */
180
+ style?: any;
181
+
182
+ /**
183
+ * Class CSS kustom untuk wrapper luar.
184
+ */
185
+ className?: string;
186
+
187
+ /**
188
+ * Class CSS kustom untuk pemicu (trigger container).
189
+ */
190
+ triggerClass?: string;
191
+
192
+ /**
193
+ * Style kustom untuk pemicu (trigger container) (UiProps).
194
+ */
195
+ triggerStyle?: UiProps;
196
+
197
+ /**
198
+ * Class CSS kustom untuk panel tooltip konten.
199
+ */
200
+ contentClass?: string;
201
+
202
+ /**
203
+ * Style kustom untuk panel tooltip konten (UiProps).
204
+ */
205
+ contentStyle?: UiProps;
206
+
207
+ /**
208
+ * Class CSS kustom untuk elemen panah (arrow).
209
+ */
210
+ arrowClass?: string;
211
+
212
+ /**
213
+ * Style kustom untuk elemen panah (arrow) (UiProps).
214
+ */
215
+ arrowStyle?: UiProps;
216
+
217
+ /**
218
+ * Callback saat status open berubah.
219
+ */
220
+ onOpenChange?: (open: boolean) => void;
221
+
222
+ /**
223
+ * Elemen pemicu (trigger) yang dibungkus oleh tooltip.
224
+ */
225
+ children?: any;
226
+ }
227
+
228
+ /**
229
+ * Komponen Tooltip untuk menampilkan informasi kontekstual singkat saat pengguna mengarahkan kursor atau memfokuskan elemen pemicu.
230
+ */
231
+
232
+ const props = defineProps<TooltipProps>();
233
+ const vm = getCurrentInstance();
234
+ const isControlled = computed(() => Boolean(vm?.vnode.props && ("open" in vm.vnode.props || "onUpdate:open" in vm.vnode.props || ":open" in vm.vnode.props)));
235
+ const isArrowControlled = computed(() => Boolean(vm?.vnode.props && ("arrow" in vm.vnode.props || ":arrow" in vm.vnode.props)));
236
+ const showArrow = computed(() => isArrowControlled.value ? props.arrow !== false : true);
237
+ const isOpen = ref(isControlled.value ? props.open : props.defaultOpen || false);
238
+
239
+ watch(
240
+ () => props.open,
241
+ (val) => {
242
+ if (isControlled.value && val !== undefined && val !== isOpen.value) {
243
+ setOpen(val);
244
+ }
245
+ }
246
+ );
247
+
248
+ const cleanupAutoUpdate = ref(null);
249
+ const openTimer = ref(null);
250
+ const closeTimer = ref(null);
251
+
252
+ const triggerRef = ref<any>(null);
253
+ const tooltipRef = ref<any>(null);
254
+ const arrowRef = ref<any>(null);
255
+
256
+ onMounted(() => {
257
+ if (props.open !== undefined) {
258
+ isOpen.value = props.open;
259
+ }
260
+ if (isOpen.value) {
261
+ setTimeout(() => {
262
+ startFloating();
263
+ updatePosition();
264
+ }, 0);
265
+ }
266
+ });
267
+ onUnmounted(() => {
268
+ clearTimers();
269
+ stopFloating();
270
+ });
271
+
272
+ function getKbdList() {
273
+ if (!props.kbd) return [];
274
+ if (Array.isArray(props.kbd)) return props.kbd;
275
+ return [props.kbd];
276
+ }
277
+ function clearTimers() {
278
+ if (openTimer.value) {
279
+ clearTimeout(openTimer.value);
280
+ openTimer.value = null;
281
+ }
282
+ if (closeTimer.value) {
283
+ clearTimeout(closeTimer.value);
284
+ closeTimer.value = null;
285
+ }
286
+ }
287
+ function setOpen(value: boolean) {
288
+ if (props.disabled && value) return;
289
+ if (!isControlled.value) {
290
+ isOpen.value = value;
291
+ }
292
+ if (props.onOpenChange) {
293
+ props.onOpenChange(value);
294
+ }
295
+ if (value) {
296
+ nextTick(() => {
297
+ startFloating();
298
+ updatePosition();
299
+ });
300
+ } else {
301
+ stopFloating();
302
+ }
303
+ }
304
+ function handlePointerEnter() {
305
+ if (props.disabled) return;
306
+ clearTimers();
307
+ const delay = props.openDelay !== undefined ? props.openDelay : 150;
308
+ if (delay <= 0) {
309
+ setOpen(true);
310
+ } else {
311
+ openTimer.value = setTimeout(() => {
312
+ setOpen(true);
313
+ }, delay);
314
+ }
315
+ }
316
+ function handlePointerLeave() {
317
+ clearTimers();
318
+ const delay = props.closeDelay !== undefined ? props.closeDelay : 100;
319
+ if (delay <= 0) {
320
+ setOpen(false);
321
+ } else {
322
+ closeTimer.value = setTimeout(() => {
323
+ setOpen(false);
324
+ }, delay);
325
+ }
326
+ }
327
+ function handleFocus() {
328
+ if (props.disabled) return;
329
+ clearTimers();
330
+ setOpen(true);
331
+ }
332
+ function handleBlur() {
333
+ clearTimers();
334
+ setOpen(false);
335
+ }
336
+ function handleKeyDown(e: any) {
337
+ if (e.key === "Escape" && isOpen.value) {
338
+ clearTimers();
339
+ setOpen(false);
340
+ }
341
+ }
342
+ function updatePosition() {
343
+ if (!triggerRef.value || !tooltipRef.value) return;
344
+ const targetPlacement = props.placement || "top";
345
+ const showArrowVal = showArrow.value;
346
+ const offsetDist =
347
+ props.offsetDistance !== undefined ? props.offsetDistance : 8;
348
+ const middleware: any[] = [
349
+ offset(offsetDist),
350
+ flip({
351
+ padding: 8,
352
+ }),
353
+ shift({
354
+ padding: 8,
355
+ }),
356
+ ];
357
+ if (showArrowVal && arrowRef.value) {
358
+ middleware.push(
359
+ floatingArrow({
360
+ element: arrowRef.value,
361
+ padding: 8,
362
+ })
363
+ );
364
+ }
365
+ computePosition(triggerRef.value, tooltipRef.value, {
366
+ placement: targetPlacement,
367
+ middleware,
368
+ }).then((data: any) => {
369
+ if (!tooltipRef.value) return;
370
+ tooltipRef.value.style.left = `${data.x}px`;
371
+ tooltipRef.value.style.top = `${data.y}px`;
372
+ const side = data.placement.split("-")[0];
373
+ tooltipRef.value.setAttribute("data-side", side);
374
+ tooltipRef.value.setAttribute("data-placement", data.placement);
375
+ if (
376
+ showArrowVal &&
377
+ arrowRef.value &&
378
+ data.middlewareData &&
379
+ data.middlewareData.arrow
380
+ ) {
381
+ const { x: arrowX, y: arrowY } = data.middlewareData.arrow;
382
+ const staticSide: any = {
383
+ top: "bottom",
384
+ right: "left",
385
+ bottom: "top",
386
+ left: "right",
387
+ }[side];
388
+ arrowRef.value.style.left = arrowX != null ? `${arrowX}px` : "";
389
+ arrowRef.value.style.top = arrowY != null ? `${arrowY}px` : "";
390
+ arrowRef.value.style.right = "";
391
+ arrowRef.value.style.bottom = "";
392
+ if (staticSide) {
393
+ arrowRef.value.style[staticSide] = "-4px";
394
+ }
395
+ }
396
+ });
397
+ }
398
+ function startFloating() {
399
+ stopFloating();
400
+ if (typeof window === "undefined") return;
401
+ if (triggerRef.value && tooltipRef.value) {
402
+ cleanupAutoUpdate.value = autoUpdate(
403
+ triggerRef.value,
404
+ tooltipRef.value,
405
+ () => {
406
+ updatePosition();
407
+ }
408
+ );
409
+ }
410
+ }
411
+ function stopFloating() {
412
+ if (cleanupAutoUpdate.value) {
413
+ cleanupAutoUpdate.value();
414
+ cleanupAutoUpdate.value = null;
415
+ }
416
+ }
417
+ </script>
@@ -0,0 +1,150 @@
1
+ /* eslint-disable */
2
+ // Auto-generated by TTDK Design System Vue Type Generator
3
+ import type { DefineComponent } from "vue";
4
+ import {
5
+ computePosition,
6
+ autoUpdate,
7
+ flip,
8
+ shift,
9
+ offset,
10
+ arrow as floatingArrow,
11
+ } from "@floating-ui/dom";
12
+ import { buildUiVars, UiProps } from "../../core/types";
13
+
14
+ export type TooltipPlacement =
15
+ | "top"
16
+ | "top-start"
17
+ | "top-end"
18
+ | "bottom"
19
+ | "bottom-start"
20
+ | "bottom-end"
21
+ | "left"
22
+ | "left-start"
23
+ | "left-end"
24
+ | "right"
25
+ | "right-start"
26
+ | "right-end";
27
+
28
+ export type TooltipUiProps = UiProps;
29
+
30
+ export interface TooltipProps {
31
+ /**
32
+ * Teks konten tooltip yang ditampilkan.
33
+ */
34
+ text?: string;
35
+
36
+ /**
37
+ * Konten kustom tooltip (JSX / VNode atau renderable content).
38
+ */
39
+ content?: any;
40
+
41
+ /**
42
+ * Pintasan keyboard opsional yang ditampilkan di dalam tooltip (misal: '⌘K', ['Ctrl', 'S']).
43
+ */
44
+ kbd?: string | string[];
45
+
46
+ /**
47
+ * Posisi penempatan tooltip terhadap elemen pemicu.
48
+ * @default 'top'
49
+ */
50
+ placement?: TooltipPlacement;
51
+
52
+ /**
53
+ * Jarak offset dalam pixel dari elemen pemicu (trigger).
54
+ * @default 8
55
+ */
56
+ offsetDistance?: number;
57
+
58
+ /**
59
+ * Menampilkan elemen panah segitiga penunjuk arah ke elemen pemicu.
60
+ * @default true
61
+ */
62
+ arrow?: boolean;
63
+
64
+ /**
65
+ * Penundaan kemunculan tooltip dalam milidetik (delay saat pointer enter).
66
+ * @default 150
67
+ */
68
+ openDelay?: number;
69
+
70
+ /**
71
+ * Penundaan hilangnya tooltip dalam milidetik (delay saat pointer leave).
72
+ * @default 100
73
+ */
74
+ closeDelay?: number;
75
+
76
+ /**
77
+ * Status visibilitas tooltip terkontrol (controlled mode).
78
+ */
79
+ open?: boolean;
80
+
81
+ /**
82
+ * Status visibilitas awal (uncontrolled initial state).
83
+ * @default false
84
+ */
85
+ defaultOpen?: boolean;
86
+
87
+ /**
88
+ * Menonaktifkan tooltip sehingga tidak muncul saat di-hover atau difokus.
89
+ * @default false
90
+ */
91
+ disabled?: boolean;
92
+
93
+ /**
94
+ * Kustomisasi visual granular container utama (UiProps).
95
+ */
96
+ ui?: TooltipUiProps;
97
+
98
+ /**
99
+ * Style inline CSS native untuk wrapper luar.
100
+ */
101
+ style?: any;
102
+
103
+ /**
104
+ * Class CSS kustom untuk wrapper luar.
105
+ */
106
+ className?: string;
107
+
108
+ /**
109
+ * Class CSS kustom untuk pemicu (trigger container).
110
+ */
111
+ triggerClass?: string;
112
+
113
+ /**
114
+ * Style kustom untuk pemicu (trigger container) (UiProps).
115
+ */
116
+ triggerStyle?: UiProps;
117
+
118
+ /**
119
+ * Class CSS kustom untuk panel tooltip konten.
120
+ */
121
+ contentClass?: string;
122
+
123
+ /**
124
+ * Style kustom untuk panel tooltip konten (UiProps).
125
+ */
126
+ contentStyle?: UiProps;
127
+
128
+ /**
129
+ * Class CSS kustom untuk elemen panah (arrow).
130
+ */
131
+ arrowClass?: string;
132
+
133
+ /**
134
+ * Style kustom untuk elemen panah (arrow) (UiProps).
135
+ */
136
+ arrowStyle?: UiProps;
137
+
138
+ /**
139
+ * Callback saat status open berubah.
140
+ */
141
+ onOpenChange?: (open: boolean) => void;
142
+
143
+ /**
144
+ * Elemen pemicu (trigger) yang dibungkus oleh tooltip.
145
+ */
146
+ children?: any;
147
+ }
148
+
149
+ declare const component: DefineComponent<TooltipProps>;
150
+ export default component;
@@ -0,0 +1,141 @@
1
+ # <BottomSheet /> — TTDK Component Reference
2
+
3
+ BottomSheet — Komponen lembar geser bawah ramah sentuhan (touch-friendly) untuk in-app webview & mobile. Mendukung safe-area-inset perangkat mobile, gesture swipe-down to dismiss, header, footer, dan mode iOS / Material.
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>/webview/bottomsheet/bottomsheet.css";`
8
+
9
+ ## 2. Subpath Component Import
10
+ ```ts
11
+ // React
12
+ import BottomSheet from "@ttdk-design-system/library-react/webview/bottomsheet";
13
+
14
+ // Vue 3
15
+ import BottomSheet from "@ttdk-design-system/library-vue/webview/bottomsheet";
16
+
17
+ // Svelte
18
+ import BottomSheet from "@ttdk-design-system/library-svelte/webview/bottomsheet";
19
+ ```
20
+
21
+ ## 3. Props & API Reference
22
+
23
+ | Prop | Type | Default | Description |
24
+ | :--- | :--- | :--- | :--- |
25
+
26
+ ### Sub-interface: `BottomSheetProps`
27
+
28
+ | Field | Type | Default | Description |
29
+ | :--- | :--- | :--- | :--- |
30
+ | `open?` | `boolean` | `-` | Status visibilitas bottom sheet (mode controlled). Mendukung `v-model:open` / `v-model` pada Vue dan controlled prop `open` pada React. |
31
+ | `defaultOpen?` | `boolean` | `false` | Status visibilitas awal bottom sheet saat pertama kali dimuat (uncontrolled initial state). |
32
+ | `title?` | `string` | `-` | Judul teks di bagian header bottom sheet. |
33
+ | `description?` | `string` | `-` | Deskripsi penjelasan di bagian header di bawah judul. |
34
+ | `height?` | `BottomSheetHeight` | `auto` | Skala ukuran tinggi bottom sheet: - `'auto'`: Menyesuaikan tinggi isi konten (maksimal 90vh). - `'sm'`: Lembar ringkas (~35% tinggi layar). - `'md'`: Lembar proporsional standar (~55% tinggi layar). - `'lg'`: Lembar luas (~85% tinggi layar). - `'full'`: Tampilan penuh (100% tinggi layar). |
35
+ | `maxHeight?` | `string` | `-` | Batas tinggi maksimum lembar sheet (contoh: '90vh', '600px'). |
36
+ | `mode?` | `BottomSheetMode` | `auto` | Cita rasa / gaya platform mobile: - `'auto'`: Desain netral adaptif khas TTDK Design System. - `'ios'`: Cita rasa Apple Human Interface (frosted glass, sudut kurva halus 20px). - `'material'`: Cita rasa Material Design 3 (sudut 28px, elevated shadow). |
37
+ | `handle?` | `boolean` | `true` | Menampilkan bilah pegangan geser (drag handle indicator) di bagian atas lembar. |
38
+ | `swipeable?` | `boolean` | `true` | Mengaktifkan gestur sentuh geser ke bawah (swipe-down) untuk menutup lembar. |
39
+ | `close?` | `boolean` | `false` | Menampilkan tombol tutup 'X' di pojok kanan atas header. |
40
+ | `closeIcon?` | `any` | `-` | Ikon kustom untuk tombol tutup. |
41
+ | `dismissible?` | `boolean` | `true` | Mengizinkan lembar ditutup saat pengguna mengeklik backdrop overlay atau menekan tombol Escape. |
42
+ | `preventClose?` | `boolean` | `false` | Mencegah lembar ditutup saat klik di luar atau saat digeser (prevent close). Jika bernilai `true`, lembar hanya dapat ditutup via aksi eksplisit. |
43
+ | `overlay?` | `boolean` | `true` | Menampilkan lapisan latar belakang redup (backdrop overlay). |
44
+ | `preventScroll?` | `boolean` | `true` | Mengunci scrolling pada halaman web di latar belakang saat lembar terbuka (body scroll lock). |
45
+ | `header?` | `any` | `-` | Konten kustom untuk bagian header lembar. |
46
+ | `body?` | `any` | `-` | Konten kustom untuk bagian isi utama (body) lembar. |
47
+ | `footer?` | `any` | `-` | Konten kustom untuk bagian footer aksi di bawah lembar (misal: tombol konfirmasi / CTA). |
48
+ | `content?` | `any` | `-` | Penggantian seluruh konten lembar (mengabaikan layout header, body, footer bawaan). |
49
+ | `children?` | `any` | `-` | Konten utama lembar bottom sheet (body content). |
50
+ | `onOpenChange?` | `(open: boolean) => void` | `-` | Callback event saat status terbuka/tertutup berubah (standar React). |
51
+ | `onUpdateOpen?` | `(open: boolean) => void` | `-` | Callback event saat status terbuka/tertutup berubah untuk two-way binding `v-model:open` (Vue). |
52
+ | `onOpen?` | `() => void` | `-` | Callback event saat lembar bottom sheet terbuka. |
53
+ | `onClose?` | `() => void` | `-` | Callback event saat lembar bottom sheet ditutup. |
54
+ | `onClosePrevent?` | `() => void` | `-` | Callback event saat pengguna mencoba menutup lembar tetapi dicegah karena `preventClose={true}`. |
55
+ | `ui?` | `BottomSheetUiProps` | `-` | Kustomisasi visual granular pada elemen root melalui style-like object. |
56
+ | `className?` | `string` | `-` | |
57
+ | `overlayClass?` | `string` | `-` | |
58
+ | `overlayStyle?` | `any` | `-` | |
59
+ | `contentClass?` | `string` | `-` | |
60
+ | `contentStyle?` | `any` | `-` | |
61
+ | `headerClass?` | `string` | `-` | |
62
+ | `headerStyle?` | `any` | `-` | |
63
+ | `bodyClass?` | `string` | `-` | |
64
+ | `bodyStyle?` | `any` | `-` | |
65
+ | `footerClass?` | `string` | `-` | |
66
+ | `footerStyle?` | `any` | `-` | |
67
+ | `handleClass?` | `string` | `-` | |
68
+ | `handleStyle?` | `any` | `-` | |
69
+
70
+ ## 4. Usage Examples
71
+
72
+ ### React Example
73
+ ```tsx
74
+ import { useState } from 'react';
75
+ import { BottomSheet } from "@ttdk-design-system/library-react/webview/bottomsheet";
76
+ import "@ttdk-design-system/library-react/webview/bottomsheet/bottomsheet.css";
77
+
78
+ export function Example() {
79
+ const [open, setOpen] = useState(false);
80
+
81
+ return (
82
+ <div>
83
+ <button onClick={() => setOpen(true)}>Buka Bottom Sheet</button>
84
+ <BottomSheet
85
+ open={open}
86
+ title="Konfirmasi Tindakan Medis"
87
+ description="Pastikan data pasien dan resep obat sudah sesuai"
88
+ onClose={() => setOpen(false)}
89
+ >
90
+ <p>Konten rincian pemeriksaan pasien dalam webview.</p>
91
+ </BottomSheet>
92
+ </div>
93
+ );
94
+ }
95
+ ```
96
+
97
+ ### Vue 3 Example
98
+ ```vue
99
+ <script setup lang="ts">
100
+ import { ref } from 'vue';
101
+ import { BottomSheet } from "@ttdk-design-system/library-vue/webview/bottomsheet";
102
+ import "@ttdk-design-system/library-vue/webview/bottomsheet/bottomsheet.css";
103
+
104
+ const open = ref(false);
105
+ </script>
106
+
107
+ <template>
108
+ <div>
109
+ <button @click="open = true">Buka Bottom Sheet</button>
110
+ <BottomSheet
111
+ v-model:open="open"
112
+ title="Konfirmasi Tindakan Medis"
113
+ description="Pastikan data pasien dan resep obat sudah sesuai"
114
+ >
115
+ <p>Konten rincian pemeriksaan pasien dalam webview.</p>
116
+ </BottomSheet>
117
+ </div>
118
+ </template>
119
+ ```
120
+
121
+ ### Svelte Example
122
+ ```svelte
123
+ <script lang="ts">
124
+ import { BottomSheet } from "@ttdk-design-system/library-svelte/webview/bottomsheet";
125
+ import "@ttdk-design-system/library-svelte/webview/bottomsheet/bottomsheet.css";
126
+
127
+ let open = false;
128
+ </script>
129
+
130
+ <div>
131
+ <button on:click={() => open = true}>Buka Bottom Sheet</button>
132
+ <BottomSheet
133
+ open={open}
134
+ title="Konfirmasi Tindakan Medis"
135
+ description="Pastikan data pasien dan resep obat sudah sesuai"
136
+ onClose={() => open = false}
137
+ >
138
+ <p>Konten rincian pemeriksaan pasien dalam webview.</p>
139
+ </BottomSheet>
140
+ </div>
141
+ ```