tekivex-ui 2.5.12 → 2.5.14

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 (231) hide show
  1. package/dist/{TkxForm-9-W3Nl6m.js → TkxForm-BaO4wvXt.js} +109 -103
  2. package/dist/{TkxForm-1KDzoniV.cjs → TkxForm-M6ttomry.cjs} +1 -1
  3. package/dist/charts.cjs +1 -1
  4. package/dist/charts.js +2 -1
  5. package/dist/headless.cjs +1 -1
  6. package/dist/headless.js +3 -2
  7. package/dist/index.cjs +10 -10
  8. package/dist/index.js +953 -896
  9. package/dist/quantum.cjs +9 -9
  10. package/dist/quantum.js +160 -115
  11. package/dist/realtime.cjs +1 -1
  12. package/dist/realtime.js +1 -1
  13. package/dist/src/charts/TkxAreaChart.d.ts.map +1 -1
  14. package/dist/src/charts/TkxBarChart.d.ts.map +1 -1
  15. package/dist/src/charts/TkxDonutChart.d.ts.map +1 -1
  16. package/dist/src/charts/TkxLineChart.d.ts.map +1 -1
  17. package/dist/src/charts/TkxPieChart.d.ts.map +1 -1
  18. package/dist/src/charts/TkxRadarChart.d.ts.map +1 -1
  19. package/dist/src/charts/TkxScatterChart.d.ts.map +1 -1
  20. package/dist/src/charts/index.d.ts.map +1 -1
  21. package/dist/src/charts/shared.d.ts.map +1 -1
  22. package/dist/src/components/TkxAIChatBubble.d.ts.map +1 -1
  23. package/dist/src/components/TkxAIConfidenceBar.d.ts.map +1 -1
  24. package/dist/src/components/TkxAIThinking.d.ts.map +1 -1
  25. package/dist/src/components/TkxAccordion.d.ts.map +1 -1
  26. package/dist/src/components/TkxAffix.d.ts.map +1 -1
  27. package/dist/src/components/TkxAlert.d.ts.map +1 -1
  28. package/dist/src/components/TkxAnchor.d.ts.map +1 -1
  29. package/dist/src/components/TkxAppBar.d.ts.map +1 -1
  30. package/dist/src/components/TkxAutocomplete.d.ts.map +1 -1
  31. package/dist/src/components/TkxAvatar.d.ts.map +1 -1
  32. package/dist/src/components/TkxBadge.d.ts.map +1 -1
  33. package/dist/src/components/TkxBottomNav.d.ts.map +1 -1
  34. package/dist/src/components/TkxBreadcrumb.d.ts.map +1 -1
  35. package/dist/src/components/TkxButton.d.ts.map +1 -1
  36. package/dist/src/components/TkxCard.d.ts.map +1 -1
  37. package/dist/src/components/TkxCarousel.d.ts.map +1 -1
  38. package/dist/src/components/TkxCascader.d.ts.map +1 -1
  39. package/dist/src/components/TkxChat.d.ts.map +1 -1
  40. package/dist/src/components/TkxCheckbox.d.ts.map +1 -1
  41. package/dist/src/components/TkxClock.d.ts.map +1 -1
  42. package/dist/src/components/TkxColorPicker.d.ts.map +1 -1
  43. package/dist/src/components/TkxCommand.d.ts.map +1 -1
  44. package/dist/src/components/TkxConfigProvider.d.ts.map +1 -1
  45. package/dist/src/components/TkxDataGrid.d.ts.map +1 -1
  46. package/dist/src/components/TkxDatePicker.d.ts +1 -1
  47. package/dist/src/components/TkxDatePicker.d.ts.map +1 -1
  48. package/dist/src/components/TkxDivider.d.ts.map +1 -1
  49. package/dist/src/components/TkxDrawer.d.ts.map +1 -1
  50. package/dist/src/components/TkxDropdown.d.ts.map +1 -1
  51. package/dist/src/components/TkxEmpty.d.ts.map +1 -1
  52. package/dist/src/components/TkxFileUpload.d.ts.map +1 -1
  53. package/dist/src/components/TkxForm.d.ts.map +1 -1
  54. package/dist/src/components/TkxIcon.d.ts.map +1 -1
  55. package/dist/src/components/TkxImage.d.ts.map +1 -1
  56. package/dist/src/components/TkxInput.d.ts.map +1 -1
  57. package/dist/src/components/TkxLayout.d.ts.map +1 -1
  58. package/dist/src/components/TkxList.d.ts.map +1 -1
  59. package/dist/src/components/TkxLiveFeed.d.ts.map +1 -1
  60. package/dist/src/components/TkxLiveLog.d.ts.map +1 -1
  61. package/dist/src/components/TkxLiveMetrics.d.ts.map +1 -1
  62. package/dist/src/components/TkxLogo.d.ts.map +1 -1
  63. package/dist/src/components/TkxMasonry.d.ts.map +1 -1
  64. package/dist/src/components/TkxMentions.d.ts.map +1 -1
  65. package/dist/src/components/TkxMenu.d.ts.map +1 -1
  66. package/dist/src/components/TkxModal.d.ts.map +1 -1
  67. package/dist/src/components/TkxNumberInput.d.ts.map +1 -1
  68. package/dist/src/components/TkxOTP.d.ts.map +1 -1
  69. package/dist/src/components/TkxPagination.d.ts.map +1 -1
  70. package/dist/src/components/TkxPlayground.d.ts +15 -1
  71. package/dist/src/components/TkxPlayground.d.ts.map +1 -1
  72. package/dist/src/components/TkxPopover.d.ts.map +1 -1
  73. package/dist/src/components/TkxProgress.d.ts.map +1 -1
  74. package/dist/src/components/TkxQRCode.d.ts.map +1 -1
  75. package/dist/src/components/TkxQuantumForm.d.ts.map +1 -1
  76. package/dist/src/components/TkxRadio.d.ts.map +1 -1
  77. package/dist/src/components/TkxRating.d.ts.map +1 -1
  78. package/dist/src/components/TkxRealTimeChart.d.ts.map +1 -1
  79. package/dist/src/components/TkxResult.d.ts.map +1 -1
  80. package/dist/src/components/TkxRichTextDisplay.d.ts.map +1 -1
  81. package/dist/src/components/TkxSegmented.d.ts.map +1 -1
  82. package/dist/src/components/TkxSelect.d.ts.map +1 -1
  83. package/dist/src/components/TkxSkeleton.d.ts.map +1 -1
  84. package/dist/src/components/TkxSlider.d.ts.map +1 -1
  85. package/dist/src/components/TkxSnackbar.d.ts.map +1 -1
  86. package/dist/src/components/TkxSpeedDial.d.ts.map +1 -1
  87. package/dist/src/components/TkxSpin.d.ts.map +1 -1
  88. package/dist/src/components/TkxStatistic.d.ts.map +1 -1
  89. package/dist/src/components/TkxStepper.d.ts.map +1 -1
  90. package/dist/src/components/TkxTable.d.ts.map +1 -1
  91. package/dist/src/components/TkxTabs.d.ts.map +1 -1
  92. package/dist/src/components/TkxTag.d.ts.map +1 -1
  93. package/dist/src/components/TkxThemeBuilder.d.ts.map +1 -1
  94. package/dist/src/components/TkxTimeline.d.ts.map +1 -1
  95. package/dist/src/components/TkxToast.d.ts.map +1 -1
  96. package/dist/src/components/TkxToggle.d.ts.map +1 -1
  97. package/dist/src/components/TkxToolbar.d.ts.map +1 -1
  98. package/dist/src/components/TkxTooltip.d.ts.map +1 -1
  99. package/dist/src/components/TkxTour.d.ts.map +1 -1
  100. package/dist/src/components/TkxTransferList.d.ts.map +1 -1
  101. package/dist/src/components/TkxTreeView.d.ts.map +1 -1
  102. package/dist/src/components/TkxTypography.d.ts.map +1 -1
  103. package/dist/src/components/TkxVideoPlayer.d.ts.map +1 -1
  104. package/dist/src/components/TkxWatermark.d.ts.map +1 -1
  105. package/dist/src/engine/security.d.ts +8 -0
  106. package/dist/src/engine/security.d.ts.map +1 -1
  107. package/dist/src/headless/index.d.ts.map +1 -1
  108. package/dist/src/headless/useControllable.d.ts.map +1 -1
  109. package/dist/src/headless/useDebounce.d.ts.map +1 -1
  110. package/dist/src/headless/useDisclosure.d.ts.map +1 -1
  111. package/dist/src/headless/useFormState.d.ts.map +1 -1
  112. package/dist/src/headless/useInfiniteQuery.d.ts.map +1 -1
  113. package/dist/src/headless/useIntersectionObserver.d.ts.map +1 -1
  114. package/dist/src/headless/useListSelection.d.ts.map +1 -1
  115. package/dist/src/headless/useLocalStorage.d.ts.map +1 -1
  116. package/dist/src/headless/useMediaQuery.d.ts.map +1 -1
  117. package/dist/src/headless/useRovingTabIndex.d.ts.map +1 -1
  118. package/dist/src/headless/useSSE.d.ts.map +1 -1
  119. package/dist/src/headless/useThrottle.d.ts.map +1 -1
  120. package/dist/src/headless/useWebSocket.d.ts.map +1 -1
  121. package/dist/src/hooks/index.d.ts.map +1 -1
  122. package/dist/tkx-BoP5V5zy.cjs +4 -0
  123. package/dist/{tkx-DQkvHdE5.js → tkx-mOKMzvUK.js} +4 -2
  124. package/package.json +3 -4
  125. package/src/charts/TkxAreaChart.tsx +3 -1
  126. package/src/charts/TkxBarChart.tsx +3 -1
  127. package/src/charts/TkxDonutChart.tsx +3 -1
  128. package/src/charts/TkxLineChart.tsx +3 -1
  129. package/src/charts/TkxPieChart.tsx +4 -2
  130. package/src/charts/TkxRadarChart.tsx +3 -1
  131. package/src/charts/TkxScatterChart.tsx +3 -1
  132. package/src/charts/index.ts +3 -1
  133. package/src/charts/shared.ts +3 -1
  134. package/src/components/TkxAIChatBubble.tsx +55 -8
  135. package/src/components/TkxAIConfidenceBar.tsx +3 -1
  136. package/src/components/TkxAIThinking.tsx +3 -1
  137. package/src/components/TkxAccordion.tsx +3 -1
  138. package/src/components/TkxAffix.tsx +3 -1
  139. package/src/components/TkxAlert.tsx +3 -1
  140. package/src/components/TkxAnchor.tsx +3 -1
  141. package/src/components/TkxAppBar.tsx +3 -1
  142. package/src/components/TkxAutocomplete.tsx +3 -1
  143. package/src/components/TkxAvatar.tsx +3 -1
  144. package/src/components/TkxBadge.tsx +3 -1
  145. package/src/components/TkxBottomNav.tsx +3 -1
  146. package/src/components/TkxBreadcrumb.tsx +3 -1
  147. package/src/components/TkxButton.tsx +3 -1
  148. package/src/components/TkxCard.tsx +3 -1
  149. package/src/components/TkxCarousel.tsx +3 -1
  150. package/src/components/TkxCascader.tsx +3 -1
  151. package/src/components/TkxChat.tsx +3 -1
  152. package/src/components/TkxCheckbox.tsx +3 -1
  153. package/src/components/TkxClock.tsx +3 -1
  154. package/src/components/TkxColorPicker.tsx +3 -1
  155. package/src/components/TkxCommand.tsx +3 -1
  156. package/src/components/TkxConfigProvider.tsx +3 -1
  157. package/src/components/TkxDataGrid.tsx +3 -1
  158. package/src/components/TkxDatePicker.tsx +76 -18
  159. package/src/components/TkxDivider.tsx +3 -1
  160. package/src/components/TkxDrawer.tsx +3 -1
  161. package/src/components/TkxDropdown.tsx +3 -1
  162. package/src/components/TkxEmpty.tsx +3 -1
  163. package/src/components/TkxFileUpload.tsx +3 -1
  164. package/src/components/TkxForm.tsx +22 -3
  165. package/src/components/TkxIcon.tsx +3 -1
  166. package/src/components/TkxImage.tsx +3 -1
  167. package/src/components/TkxInput.tsx +3 -1
  168. package/src/components/TkxLayout.tsx +3 -1
  169. package/src/components/TkxList.tsx +3 -1
  170. package/src/components/TkxLiveFeed.tsx +3 -1
  171. package/src/components/TkxLiveLog.tsx +3 -1
  172. package/src/components/TkxLiveMetrics.tsx +3 -1
  173. package/src/components/TkxLogo.tsx +3 -1
  174. package/src/components/TkxMasonry.tsx +3 -1
  175. package/src/components/TkxMentions.tsx +3 -1
  176. package/src/components/TkxMenu.tsx +3 -1
  177. package/src/components/TkxModal.tsx +3 -1
  178. package/src/components/TkxNumberInput.tsx +3 -1
  179. package/src/components/TkxOTP.tsx +3 -1
  180. package/src/components/TkxPagination.tsx +3 -1
  181. package/src/components/TkxPlayground.tsx +77 -3
  182. package/src/components/TkxPopover.tsx +3 -1
  183. package/src/components/TkxProgress.tsx +3 -1
  184. package/src/components/TkxQRCode.tsx +3 -1
  185. package/src/components/TkxQuantumForm.tsx +3 -1
  186. package/src/components/TkxRadio.tsx +3 -1
  187. package/src/components/TkxRating.tsx +3 -1
  188. package/src/components/TkxRealTimeChart.tsx +3 -1
  189. package/src/components/TkxResult.tsx +3 -1
  190. package/src/components/TkxRichTextDisplay.tsx +3 -1
  191. package/src/components/TkxSegmented.tsx +3 -1
  192. package/src/components/TkxSelect.tsx +3 -1
  193. package/src/components/TkxSkeleton.tsx +3 -1
  194. package/src/components/TkxSlider.tsx +3 -1
  195. package/src/components/TkxSnackbar.tsx +3 -1
  196. package/src/components/TkxSpeedDial.tsx +3 -1
  197. package/src/components/TkxSpin.tsx +3 -1
  198. package/src/components/TkxStatistic.tsx +3 -1
  199. package/src/components/TkxStepper.tsx +3 -1
  200. package/src/components/TkxTable.tsx +3 -1
  201. package/src/components/TkxTabs.tsx +3 -1
  202. package/src/components/TkxTag.tsx +3 -1
  203. package/src/components/TkxThemeBuilder.tsx +3 -1
  204. package/src/components/TkxTimeline.tsx +3 -1
  205. package/src/components/TkxToast.tsx +3 -1
  206. package/src/components/TkxToggle.tsx +3 -1
  207. package/src/components/TkxToolbar.tsx +3 -1
  208. package/src/components/TkxTooltip.tsx +15 -2
  209. package/src/components/TkxTour.tsx +3 -1
  210. package/src/components/TkxTransferList.tsx +3 -1
  211. package/src/components/TkxTreeView.tsx +3 -1
  212. package/src/components/TkxTypography.tsx +3 -1
  213. package/src/components/TkxVideoPlayer.tsx +3 -1
  214. package/src/components/TkxWatermark.tsx +3 -1
  215. package/src/engine/security.ts +16 -1
  216. package/src/headless/index.ts +3 -1
  217. package/src/headless/useControllable.ts +3 -1
  218. package/src/headless/useDebounce.ts +3 -1
  219. package/src/headless/useDisclosure.ts +3 -1
  220. package/src/headless/useFormState.ts +3 -1
  221. package/src/headless/useInfiniteQuery.ts +3 -1
  222. package/src/headless/useIntersectionObserver.ts +3 -1
  223. package/src/headless/useListSelection.ts +3 -1
  224. package/src/headless/useLocalStorage.ts +3 -1
  225. package/src/headless/useMediaQuery.ts +3 -1
  226. package/src/headless/useRovingTabIndex.ts +3 -1
  227. package/src/headless/useSSE.ts +3 -1
  228. package/src/headless/useThrottle.ts +3 -1
  229. package/src/headless/useWebSocket.ts +3 -1
  230. package/src/hooks/index.ts +3 -1
  231. package/dist/tkx-0oAwZqgL.cjs +0 -4
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { forwardRef, type ReactNode, type SVGAttributes } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { tkx, cx } from '../engine/tkx';
@@ -680,4 +682,4 @@ export const ICON_CATEGORIES: Record<string, IconName[]> = {
680
682
  'file', 'file-text', 'folder', 'folder-open', 'code', 'terminal',
681
683
  'lock', 'unlock', 'key', 'shield',
682
684
  ],
683
- };
685
+ };
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -274,4 +276,4 @@ export function TkxImage({
274
276
  {lightbox}
275
277
  </>
276
278
  );
277
- }
279
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { forwardRef, useId, type InputHTMLAttributes, type ReactNode } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -98,4 +100,4 @@ export const TkxInput = forwardRef<HTMLInputElement, TkxInputProps>(
98
100
  },
99
101
  );
100
102
 
101
- TkxInput.displayName = 'TkxInput';
103
+ TkxInput.displayName = 'TkxInput';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  forwardRef,
3
5
  createContext,
@@ -644,4 +646,4 @@ TkxCol.displayName = 'TkxCol';
644
646
  // </TkxLayout>
645
647
  // <TkxFooter>Footer</TkxFooter>
646
648
  // </TkxLayout>
647
- // ══════════════════════════════════════════════════════════════════════════════
649
+ // ══════════════════════════════════════════════════════════════════════════════
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { type ReactNode } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -239,4 +241,4 @@ export function TkxList({
239
241
  )}
240
242
  </div>
241
243
  );
242
- }
244
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -326,4 +328,4 @@ export function TkxLiveFeed({
326
328
  }
327
329
 
328
330
  // Ensure tkx is referenced (satisfies import requirement)
329
- void tkx;
331
+ void tkx;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -467,4 +469,4 @@ export function TkxLiveLog({
467
469
  }
468
470
 
469
471
  // Satisfy import requirement
470
- void tkx;
472
+ void tkx;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -310,4 +312,4 @@ export function TkxLiveMetrics({
310
312
  }
311
313
 
312
314
  // Satisfy import requirement
313
- void tkx;
315
+ void tkx;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { type ReactNode, type CSSProperties } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { useReducedMotion } from '../hooks';
@@ -294,4 +296,4 @@ function splitBrand(
294
296
  <span style={{ color: primaryColor }}>{text.slice(split)}</span>
295
297
  </>
296
298
  );
297
- }
299
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -173,4 +175,4 @@ export function TkxMasonry({
173
175
  ))}
174
176
  </div>
175
177
  );
176
- }
178
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { type ReactNode, useState, useRef, useCallback, useEffect } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -207,4 +209,4 @@ export function TkxMentions({
207
209
  )}
208
210
  </div>
209
211
  );
210
- }
212
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -1039,4 +1041,4 @@ export function TkxMenu({
1039
1041
  );
1040
1042
  }
1041
1043
 
1042
- TkxMenu.displayName = 'TkxMenu';
1044
+ TkxMenu.displayName = 'TkxMenu';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { useEffect, useId, type ReactNode } from 'react';
2
4
  import { createPortal } from 'react-dom';
3
5
  import { useTheme } from '../themes';
@@ -117,4 +119,4 @@ export function TkxModal({ isOpen, onClose, title, size = 'md', closeOnOverlayCl
117
119
  </div>,
118
120
  document.body,
119
121
  );
120
- }
122
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -405,4 +407,4 @@ export function TkxNumberInput({
405
407
  );
406
408
  }
407
409
 
408
- TkxNumberInput.displayName = 'TkxNumberInput';
410
+ TkxNumberInput.displayName = 'TkxNumberInput';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -292,4 +294,4 @@ export function TkxOTP({
292
294
  );
293
295
  }
294
296
 
295
- TkxOTP.displayName = 'TkxOTP';
297
+ TkxOTP.displayName = 'TkxOTP';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { useState, useId } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { tkx } from '../engine/tkx';
@@ -385,4 +387,4 @@ export function TkxPagination({
385
387
  );
386
388
  }
387
389
 
388
- TkxPagination.displayName = 'TkxPagination';
390
+ TkxPagination.displayName = 'TkxPagination';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  // ── TkxPlayground ─────────────────────────────────────────────────────────────
2
4
  // In-browser live component playground. Type JSX, see it render instantly.
3
5
  // Uses new Function() evaluation, an error boundary, quantum component
@@ -43,6 +45,56 @@ export interface TkxPlaygroundProps {
43
45
  examples?: PlaygroundExample[];
44
46
  height?: number;
45
47
  imports?: Record<string, unknown>;
48
+ /**
49
+ * When true, reject code containing high-risk tokens (fetch, XMLHttpRequest,
50
+ * document.cookie, localStorage, sessionStorage, import(), window.*, eval).
51
+ * Defense-in-depth — not a true sandbox. Default: true.
52
+ *
53
+ * Set to `false` only in trusted developer environments where the playground
54
+ * input cannot come from an untrusted third party.
55
+ */
56
+ strictMode?: boolean;
57
+ /**
58
+ * Additional forbidden substrings appended to the default deny list
59
+ * (when strictMode is on).
60
+ */
61
+ forbiddenTokens?: string[];
62
+ }
63
+
64
+ // Conservative deny list for strictMode. These patterns signal network
65
+ // exfiltration, storage access, or global-scope escape — capabilities that
66
+ // live-playground snippets should never need. Matching is substring-based
67
+ // and case-insensitive; it is intentionally coarse (false-positives are
68
+ // acceptable when the alternative is arbitrary code execution).
69
+ const DEFAULT_FORBIDDEN_TOKENS = [
70
+ 'fetch(',
71
+ 'XMLHttpRequest',
72
+ 'navigator.sendBeacon',
73
+ 'document.cookie',
74
+ 'localStorage',
75
+ 'sessionStorage',
76
+ 'indexedDB',
77
+ 'WebSocket',
78
+ 'EventSource',
79
+ 'import(',
80
+ 'eval(',
81
+ 'new Function(',
82
+ 'postMessage',
83
+ 'window.open',
84
+ 'location.href',
85
+ 'location.replace',
86
+ 'location.assign',
87
+ 'document.write',
88
+ 'crypto.subtle',
89
+ ];
90
+
91
+ function detectForbiddenToken(code: string, extra?: string[]): string | null {
92
+ const needles = [...DEFAULT_FORBIDDEN_TOKENS, ...(extra ?? [])];
93
+ const lower = code.toLowerCase();
94
+ for (const n of needles) {
95
+ if (lower.includes(n.toLowerCase())) return n;
96
+ }
97
+ return null;
46
98
  }
47
99
 
48
100
  // ── Built-in examples ─────────────────────────────────────────────────────────
@@ -194,11 +246,31 @@ function getBabel(): BabelStandalone | null {
194
246
  function evalCode(
195
247
  code: string,
196
248
  importsObj: Record<string, unknown>,
249
+ opts?: { strictMode?: boolean; forbiddenTokens?: string[] },
197
250
  ): { element: ReactNode | null; error: string | null; renderMs: number } {
198
251
  const t0 = performance.now();
199
252
  try {
200
253
  const trimmed = code.trim();
201
254
 
255
+ // Strict-mode defense: block high-risk tokens before evaluation.
256
+ // Not a sandbox — a layer of protection against accidental exfiltration
257
+ // when a playground is wired to untrusted input (e.g. shared snippets).
258
+ if (opts?.strictMode !== false) {
259
+ const hit = detectForbiddenToken(trimmed, opts?.forbiddenTokens);
260
+ if (hit) {
261
+ const renderMs = parseFloat((performance.now() - t0).toFixed(2));
262
+ return {
263
+ element: null,
264
+ error:
265
+ `Blocked by playground strictMode: code contains "${hit}". ` +
266
+ `This token is disallowed because playground snippets run in the ` +
267
+ `page's JavaScript context. If you trust the source, pass ` +
268
+ `strictMode={false} to <TkxPlayground>.`,
269
+ renderMs,
270
+ };
271
+ }
272
+ }
273
+
202
274
  // Always wrap user code in a function component so React hooks (useState,
203
275
  // useEffect, ...) work — they require an active render context to dispatch.
204
276
  // The user can write a single JSX expression OR a function body that returns JSX.
@@ -335,6 +407,8 @@ export function TkxPlayground({
335
407
  examples: userExamples,
336
408
  height = 480,
337
409
  imports = {},
410
+ strictMode = true,
411
+ forbiddenTokens,
338
412
  }: TkxPlaygroundProps) {
339
413
  const theme = useTheme();
340
414
  const allExamples = [...BUILT_IN_EXAMPLES, ...(userExamples ?? [])];
@@ -359,10 +433,10 @@ export function TkxPlayground({
359
433
  const runEval = useCallback(
360
434
  (src: string) => {
361
435
  setBoundaryError(null);
362
- const result = evalCode(src, imports);
436
+ const result = evalCode(src, imports, { strictMode, forbiddenTokens });
363
437
  setPreview(result);
364
438
  },
365
- [imports],
439
+ [imports, strictMode, forbiddenTokens],
366
440
  );
367
441
 
368
442
  useEffect(() => {
@@ -768,4 +842,4 @@ export function TkxPlayground({
768
842
  );
769
843
  }
770
844
 
771
- TkxPlayground.displayName = 'TkxPlayground';
845
+ TkxPlayground.displayName = 'TkxPlayground';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -292,4 +294,4 @@ export function TkxPopover({
292
294
  );
293
295
  }
294
296
 
295
- export default TkxPopover;
297
+ export default TkxPopover;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { forwardRef, type HTMLAttributes } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { useReducedMotion } from '../hooks';
@@ -109,4 +111,4 @@ export const TkxProgress = forwardRef<HTMLDivElement, TkxProgressProps>(
109
111
  },
110
112
  );
111
113
 
112
- TkxProgress.displayName = 'TkxProgress';
114
+ TkxProgress.displayName = 'TkxProgress';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { useRef, useEffect, useMemo } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -171,4 +173,4 @@ export function TkxQRCode({
171
173
  />
172
174
  </div>
173
175
  );
174
- }
176
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  // ── TkxQuantumForm ────────────────────────────────────────────────────────────
2
4
  // Quantum-AI powered smart form. Field types, validation rules, labels, and
3
5
  // placeholders are automatically inferred from field names via
@@ -589,4 +591,4 @@ export function TkxQuantumForm({
589
591
  );
590
592
  }
591
593
 
592
- TkxQuantumForm.displayName = 'TkxQuantumForm';
594
+ TkxQuantumForm.displayName = 'TkxQuantumForm';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  createContext,
3
5
  useContext,
@@ -281,4 +283,4 @@ export function TkxRadioGroup({
281
283
  </div>
282
284
  </RadioGroupContext.Provider>
283
285
  );
284
- }
286
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -283,4 +285,4 @@ export function TkxRating({
283
285
  )}
284
286
  </div>
285
287
  );
286
- }
288
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -378,4 +380,4 @@ export function TkxRealTimeChart({
378
380
 
379
381
  // Satisfy import requirement
380
382
  void tkx;
381
- void sanitizeString;
383
+ void sanitizeString;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { type ReactNode } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -125,4 +127,4 @@ export function TkxResult({ status, title, subTitle, icon, extra }: TkxResultPro
125
127
  )}
126
128
  </div>
127
129
  );
128
- }
130
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useMemo,
3
5
  type ReactNode,
@@ -391,4 +393,4 @@ export function TkxRichTextDisplay({
391
393
  {renderedBlocks}
392
394
  </article>
393
395
  );
394
- }
396
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { type ReactNode, useState, useRef, useEffect, useCallback } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -166,4 +168,4 @@ export function TkxSegmented({
166
168
  })}
167
169
  </div>
168
170
  );
169
- }
171
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -1125,4 +1127,4 @@ export function TkxSelect({
1125
1127
  );
1126
1128
  }
1127
1129
 
1128
- TkxSelect.displayName = 'TkxSelect';
1130
+ TkxSelect.displayName = 'TkxSelect';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { forwardRef, type HTMLAttributes } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { useReducedMotion } from '../hooks';
@@ -102,4 +104,4 @@ export const TkxSkeleton = forwardRef<HTMLDivElement, TkxSkeletonProps>(
102
104
  },
103
105
  );
104
106
 
105
- TkxSkeleton.displayName = 'TkxSkeleton';
107
+ TkxSkeleton.displayName = 'TkxSkeleton';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -490,4 +492,4 @@ export function TkxSlider({
490
492
  );
491
493
  }
492
494
 
493
- TkxSlider.displayName = 'TkxSlider';
495
+ TkxSlider.displayName = 'TkxSlider';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -311,4 +313,4 @@ export function TkxSnackbar({
311
313
  </div>,
312
314
  document.body,
313
315
  );
314
- }
316
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -392,4 +394,4 @@ export function TkxSpeedDial({
392
394
  );
393
395
  }
394
396
 
395
- export default TkxSpeedDial;
397
+ export default TkxSpeedDial;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -258,4 +260,4 @@ export function TkxSpin({
258
260
  },
259
261
  spinnerContent,
260
262
  );
261
- }
263
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { useState, useEffect, useRef, type ReactNode, type CSSProperties, createElement } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { sanitizeString } from '../engine/security';
@@ -258,4 +260,4 @@ export function TkxCountdown({
258
260
  ),
259
261
  ),
260
262
  );
261
- }
263
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  type CSSProperties,
3
5
  type ReactNode,
@@ -482,4 +484,4 @@ export function TkxStepper({
482
484
  );
483
485
  }
484
486
 
485
- TkxStepper.displayName = 'TkxStepper';
487
+ TkxStepper.displayName = 'TkxStepper';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -419,4 +421,4 @@ export function TkxTable<T extends Record<string, unknown>>({
419
421
  </div>
420
422
  </div>
421
423
  );
422
- }
424
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { createContext, useContext, useState, useRef, useId, type ReactNode, type HTMLAttributes } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { handleTabsKeyboard } from '../engine/wcag';
@@ -121,4 +123,4 @@ export function TkxTabPanel({ index, children, style, className }: TkxTabPanelPr
121
123
  {children}
122
124
  </div>
123
125
  );
124
- }
126
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useRef,
@@ -316,4 +318,4 @@ export function TkxTagInput({
316
318
  )}
317
319
  </div>
318
320
  );
319
- }
321
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  // ══════════════════════════════════════════════════════════════════════════════
2
4
  // TkxThemeBuilder — Quantum-powered visual theme builder component
3
5
  // Uses real quantum annealing to optimize color palettes.
@@ -682,4 +684,4 @@ export function TkxThemeBuilder({
682
684
  );
683
685
  }
684
686
 
685
- export default TkxThemeBuilder;
687
+ export default TkxThemeBuilder;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { useEffect, useRef, type ReactNode } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { tkx, cx } from '../engine/tkx';
@@ -300,4 +302,4 @@ export function TkxTimeline({
300
302
  })}
301
303
  </div>
302
304
  );
303
- }
305
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useState,
3
5
  useEffect,
@@ -282,4 +284,4 @@ export function TkxToastProvider({ position = 'top-right', children }: TkxToastP
282
284
  </div>,
283
285
  document.body,
284
286
  )}</>;
285
- }
287
+ }
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { forwardRef, useId, type ButtonHTMLAttributes } from 'react';
2
4
  import { useTheme } from '../themes';
3
5
  import { useReducedMotion } from '../hooks';
@@ -90,4 +92,4 @@ export const TkxToggle = forwardRef<HTMLButtonElement, TkxToggleProps>(
90
92
  },
91
93
  );
92
94
 
93
- TkxToggle.displayName = 'TkxToggle';
95
+ TkxToggle.displayName = 'TkxToggle';
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import {
2
4
  useRef,
3
5
  useCallback,
@@ -257,4 +259,4 @@ export function TkxToolbar({
257
259
  );
258
260
  }
259
261
 
260
- export default TkxToolbar;
262
+ export default TkxToolbar;