@rangka/client 0.1.1 → 0.1.3

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 (317) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/App.js +7 -1
  3. package/dist/App.js.map +1 -1
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -0
  7. package/dist/index.js.map +1 -1
  8. package/dist/main.d.ts.map +1 -1
  9. package/dist/main.js +20 -0
  10. package/dist/main.js.map +1 -1
  11. package/dist/shell/assets/index-63v1sBS3.css +1 -0
  12. package/dist/shell/assets/index-Dh7K40cQ.js +8634 -0
  13. package/dist/shell/assets/vendor-query-B2cydN5j.js +1 -0
  14. package/dist/shell/assets/vendor-radix-BJxYPxPb.js +69 -0
  15. package/dist/shell/assets/vendor-router-ET_myMt5.js +17 -0
  16. package/dist/shell/index.html +5 -2
  17. package/dist/theme.css +82 -0
  18. package/dist/widgets/components/lazy-manifest.d.ts +11 -0
  19. package/dist/widgets/components/lazy-manifest.d.ts.map +1 -0
  20. package/dist/widgets/components/lazy-manifest.js +32 -0
  21. package/dist/widgets/components/lazy-manifest.js.map +1 -0
  22. package/dist/widgets/components/register.js +12 -12
  23. package/dist/widgets/components/register.js.map +1 -1
  24. package/dist/widgets/loader.d.ts +3 -0
  25. package/dist/widgets/loader.d.ts.map +1 -0
  26. package/dist/widgets/loader.js +73 -0
  27. package/dist/widgets/loader.js.map +1 -0
  28. package/dist/widgets/renderer/LazyWidget.d.ts +8 -0
  29. package/dist/widgets/renderer/LazyWidget.d.ts.map +1 -0
  30. package/dist/widgets/renderer/LazyWidget.js +31 -0
  31. package/dist/widgets/renderer/LazyWidget.js.map +1 -0
  32. package/dist/widgets/renderer/WidgetErrorBoundary.d.ts +17 -0
  33. package/dist/widgets/renderer/WidgetErrorBoundary.d.ts.map +1 -0
  34. package/dist/widgets/renderer/WidgetErrorBoundary.js +18 -0
  35. package/dist/widgets/renderer/WidgetErrorBoundary.js.map +1 -0
  36. package/dist/widgets/renderer/WidgetRenderer.d.ts.map +1 -1
  37. package/dist/widgets/renderer/WidgetRenderer.js +8 -6
  38. package/dist/widgets/renderer/WidgetRenderer.js.map +1 -1
  39. package/package.json +7 -4
  40. package/.claude/skills/add-widget/SKILL.md +0 -101
  41. package/.turbo/turbo-build.log +0 -29
  42. package/CHANGELOG.md +0 -25
  43. package/CLAUDE.md +0 -236
  44. package/components.json +0 -25
  45. package/dist/components/ui/chart.d.ts +0 -45
  46. package/dist/components/ui/chart.d.ts.map +0 -1
  47. package/dist/components/ui/chart.js +0 -119
  48. package/dist/components/ui/chart.js.map +0 -1
  49. package/dist/shell/assets/index--35CAvcP.js +0 -8715
  50. package/dist/shell/assets/index-COLmoPYo.css +0 -1
  51. package/index.html +0 -12
  52. package/src/App.tsx +0 -44
  53. package/src/__tests__/setup.ts +0 -1
  54. package/src/api/auth.ts +0 -41
  55. package/src/api/boot.ts +0 -10
  56. package/src/api/client.ts +0 -26
  57. package/src/api/paths.ts +0 -3
  58. package/src/api/token.ts +0 -13
  59. package/src/auth/LoginForm.tsx +0 -67
  60. package/src/auth/SessionExpired.tsx +0 -24
  61. package/src/auth/SetupForm.tsx +0 -76
  62. package/src/boot/BootGate.tsx +0 -35
  63. package/src/boot/BootProvider.tsx +0 -28
  64. package/src/boot/types.ts +0 -9
  65. package/src/boot/useBoot.ts +0 -111
  66. package/src/components/Icon.tsx +0 -17
  67. package/src/components/ui/accordion.tsx +0 -82
  68. package/src/components/ui/alert-dialog.tsx +0 -180
  69. package/src/components/ui/alert.tsx +0 -76
  70. package/src/components/ui/aspect-ratio.tsx +0 -9
  71. package/src/components/ui/avatar.tsx +0 -94
  72. package/src/components/ui/badge.tsx +0 -45
  73. package/src/components/ui/breadcrumb.tsx +0 -104
  74. package/src/components/ui/button-group.tsx +0 -78
  75. package/src/components/ui/button.tsx +0 -65
  76. package/src/components/ui/calendar.tsx +0 -187
  77. package/src/components/ui/card.tsx +0 -85
  78. package/src/components/ui/carousel.tsx +0 -229
  79. package/src/components/ui/chart.tsx +0 -339
  80. package/src/components/ui/checkbox.tsx +0 -27
  81. package/src/components/ui/collapsible.tsx +0 -21
  82. package/src/components/ui/combobox.tsx +0 -275
  83. package/src/components/ui/command.tsx +0 -178
  84. package/src/components/ui/context-menu.tsx +0 -242
  85. package/src/components/ui/dialog.tsx +0 -146
  86. package/src/components/ui/direction.tsx +0 -20
  87. package/src/components/ui/drawer.tsx +0 -118
  88. package/src/components/ui/dropdown-menu.tsx +0 -247
  89. package/src/components/ui/empty.tsx +0 -94
  90. package/src/components/ui/field.tsx +0 -224
  91. package/src/components/ui/hover-card.tsx +0 -36
  92. package/src/components/ui/input-group.tsx +0 -142
  93. package/src/components/ui/input-otp.tsx +0 -86
  94. package/src/components/ui/input.tsx +0 -19
  95. package/src/components/ui/item.tsx +0 -182
  96. package/src/components/ui/kbd.tsx +0 -26
  97. package/src/components/ui/label.tsx +0 -19
  98. package/src/components/ui/menubar.tsx +0 -260
  99. package/src/components/ui/native-select.tsx +0 -55
  100. package/src/components/ui/navigation-menu.tsx +0 -160
  101. package/src/components/ui/pagination.tsx +0 -112
  102. package/src/components/ui/popover.tsx +0 -74
  103. package/src/components/ui/progress.tsx +0 -31
  104. package/src/components/ui/radio-group.tsx +0 -42
  105. package/src/components/ui/resizable.tsx +0 -42
  106. package/src/components/ui/scroll-area.tsx +0 -53
  107. package/src/components/ui/select.tsx +0 -185
  108. package/src/components/ui/separator.tsx +0 -26
  109. package/src/components/ui/sheet.tsx +0 -128
  110. package/src/components/ui/sidebar.tsx +0 -669
  111. package/src/components/ui/skeleton.tsx +0 -13
  112. package/src/components/ui/slider.tsx +0 -54
  113. package/src/components/ui/sonner.tsx +0 -43
  114. package/src/components/ui/spinner.tsx +0 -16
  115. package/src/components/ui/switch.tsx +0 -33
  116. package/src/components/ui/table.tsx +0 -87
  117. package/src/components/ui/tabs.tsx +0 -80
  118. package/src/components/ui/textarea.tsx +0 -18
  119. package/src/components/ui/toggle-group.tsx +0 -86
  120. package/src/components/ui/toggle.tsx +0 -44
  121. package/src/components/ui/tooltip.tsx +0 -53
  122. package/src/context/MetaContext.tsx +0 -22
  123. package/src/context/ModuleContext.tsx +0 -62
  124. package/src/context/PermissionsContext.tsx +0 -39
  125. package/src/context/ShellProviders.tsx +0 -33
  126. package/src/context/UserContext.tsx +0 -16
  127. package/src/data/QueryProvider.tsx +0 -7
  128. package/src/data/queryClient.ts +0 -18
  129. package/src/data/useModelMeta.ts +0 -17
  130. package/src/data/useMutation.ts +0 -60
  131. package/src/data/useRecord.ts +0 -29
  132. package/src/data/useSource.ts +0 -112
  133. package/src/hooks/use-mobile.ts +0 -19
  134. package/src/index.css +0 -260
  135. package/src/index.ts +0 -16
  136. package/src/lib/utils.ts +0 -6
  137. package/src/main.tsx +0 -17
  138. package/src/router/NotFound.tsx +0 -8
  139. package/src/router/RouterProvider.tsx +0 -7
  140. package/src/router/buildRouteTree.tsx +0 -63
  141. package/src/router/createShellRouter.ts +0 -9
  142. package/src/router/hooks.ts +0 -43
  143. package/src/shell/CommandPalette.tsx +0 -76
  144. package/src/shell/ConfirmDialog.tsx +0 -34
  145. package/src/shell/ConfirmProvider.tsx +0 -56
  146. package/src/shell/DrawerContext.tsx +0 -44
  147. package/src/shell/HeaderActions.tsx +0 -31
  148. package/src/shell/ModuleSelectorPage.tsx +0 -149
  149. package/src/shell/PageOutlet.tsx +0 -21
  150. package/src/shell/ShellContext.tsx +0 -45
  151. package/src/shell/ShellDevTools.tsx +0 -153
  152. package/src/shell/ShellLayout.tsx +0 -231
  153. package/src/shell/Toast.tsx +0 -58
  154. package/src/shell/ToastProvider.tsx +0 -60
  155. package/src/shell/app-sidebar/AppSidebar.tsx +0 -44
  156. package/src/shell/app-sidebar/ModuleSwitcher.tsx +0 -87
  157. package/src/shell/app-sidebar/NavMain.tsx +0 -64
  158. package/src/shell/app-sidebar/NavUser.tsx +0 -97
  159. package/src/shell/app-sidebar/SearchMenu.tsx +0 -22
  160. package/src/shell/app-sidebar/index.ts +0 -8
  161. package/src/shell/app-sidebar/types.ts +0 -38
  162. package/src/shell/types.ts +0 -6
  163. package/src/shell/useBreadcrumbs.ts +0 -42
  164. package/src/studio/bridge.ts +0 -125
  165. package/src/studio/index.ts +0 -3
  166. package/src/studio/overlay.ts +0 -47
  167. package/src/studio/types.ts +0 -32
  168. package/src/studio/walker.ts +0 -48
  169. package/src/vite-env.d.ts +0 -1
  170. package/src/widgets/__tests__/action-edge-cases.test.ts +0 -281
  171. package/src/widgets/__tests__/action.test.ts +0 -236
  172. package/src/widgets/__tests__/attachment-widget.test.tsx +0 -85
  173. package/src/widgets/__tests__/attachments-widget.test.tsx +0 -109
  174. package/src/widgets/__tests__/binding.test.ts +0 -76
  175. package/src/widgets/__tests__/button-widget.test.tsx +0 -145
  176. package/src/widgets/__tests__/checkbox-widget.test.tsx +0 -158
  177. package/src/widgets/__tests__/code-widget.test.tsx +0 -64
  178. package/src/widgets/__tests__/computed-widget.test.tsx +0 -62
  179. package/src/widgets/__tests__/condition-edge-cases.test.ts +0 -120
  180. package/src/widgets/__tests__/condition.test.ts +0 -221
  181. package/src/widgets/__tests__/context.test.ts +0 -99
  182. package/src/widgets/__tests__/data-widget.test.tsx +0 -204
  183. package/src/widgets/__tests__/datepicker-widget.test.tsx +0 -66
  184. package/src/widgets/__tests__/datetime-widget.test.tsx +0 -67
  185. package/src/widgets/__tests__/drawer-widget.test.tsx +0 -149
  186. package/src/widgets/__tests__/dynamic-link-widget.test.tsx +0 -52
  187. package/src/widgets/__tests__/edge-cases.test.ts +0 -232
  188. package/src/widgets/__tests__/evaluator.test.ts +0 -107
  189. package/src/widgets/__tests__/functions.test.ts +0 -147
  190. package/src/widgets/__tests__/grid-widget.test.tsx +0 -137
  191. package/src/widgets/__tests__/hooks.test.tsx +0 -249
  192. package/src/widgets/__tests__/icon-widget.test.tsx +0 -129
  193. package/src/widgets/__tests__/input-widget.test.tsx +0 -264
  194. package/src/widgets/__tests__/integration.test.ts +0 -116
  195. package/src/widgets/__tests__/json-widget.test.tsx +0 -70
  196. package/src/widgets/__tests__/link-widget.test.tsx +0 -92
  197. package/src/widgets/__tests__/many-to-many-widget.test.tsx +0 -93
  198. package/src/widgets/__tests__/modal-widget.test.tsx +0 -148
  199. package/src/widgets/__tests__/money-widget.test.tsx +0 -97
  200. package/src/widgets/__tests__/parser.test.ts +0 -171
  201. package/src/widgets/__tests__/reactive-variables.test.ts +0 -383
  202. package/src/widgets/__tests__/renderer.test.tsx +0 -300
  203. package/src/widgets/__tests__/repeat-widget.test.tsx +0 -229
  204. package/src/widgets/__tests__/select-widget.test.tsx +0 -231
  205. package/src/widgets/__tests__/sequence-widget.test.tsx +0 -58
  206. package/src/widgets/__tests__/shell-integration.test.tsx +0 -1343
  207. package/src/widgets/__tests__/split-widget.test.tsx +0 -133
  208. package/src/widgets/__tests__/state-edge-cases.test.ts +0 -118
  209. package/src/widgets/__tests__/state.test.ts +0 -106
  210. package/src/widgets/__tests__/table-data-binding.test.tsx +0 -482
  211. package/src/widgets/__tests__/table-filter-popover.test.tsx +0 -486
  212. package/src/widgets/__tests__/table-search.test.tsx +0 -305
  213. package/src/widgets/__tests__/table-widget.test.tsx +0 -509
  214. package/src/widgets/__tests__/textarea-widget.test.tsx +0 -105
  215. package/src/widgets/__tests__/tracker-validator-edge-cases.test.ts +0 -242
  216. package/src/widgets/__tests__/tracker.test.ts +0 -133
  217. package/src/widgets/__tests__/tree-widget.test.tsx +0 -97
  218. package/src/widgets/__tests__/use-model-source.test.ts +0 -67
  219. package/src/widgets/__tests__/validator.test.ts +0 -208
  220. package/src/widgets/action/dispatcher.ts +0 -334
  221. package/src/widgets/action/index.ts +0 -2
  222. package/src/widgets/binding/index.ts +0 -2
  223. package/src/widgets/binding/resolver.ts +0 -61
  224. package/src/widgets/components/AttachmentWidget.tsx +0 -111
  225. package/src/widgets/components/AttachmentsWidget.tsx +0 -121
  226. package/src/widgets/components/BadgeWidget.tsx +0 -35
  227. package/src/widgets/components/ButtonWidget.tsx +0 -43
  228. package/src/widgets/components/CardWidget.tsx +0 -68
  229. package/src/widgets/components/CheckboxWidget.tsx +0 -39
  230. package/src/widgets/components/CodeWidget.tsx +0 -44
  231. package/src/widgets/components/ColumnWidget.tsx +0 -22
  232. package/src/widgets/components/ComputedWidget.tsx +0 -49
  233. package/src/widgets/components/DataWidget.tsx +0 -189
  234. package/src/widgets/components/DatePickerWidget.tsx +0 -73
  235. package/src/widgets/components/DatetimeWidget.tsx +0 -160
  236. package/src/widgets/components/DividerWidget.tsx +0 -37
  237. package/src/widgets/components/DrawerWidget.tsx +0 -52
  238. package/src/widgets/components/DynamicLinkWidget.tsx +0 -130
  239. package/src/widgets/components/GridWidget.tsx +0 -134
  240. package/src/widgets/components/GroupWidget.tsx +0 -111
  241. package/src/widgets/components/IconWidget.tsx +0 -29
  242. package/src/widgets/components/ImageWidget.tsx +0 -28
  243. package/src/widgets/components/InputWidget.tsx +0 -70
  244. package/src/widgets/components/JsonWidget.tsx +0 -78
  245. package/src/widgets/components/LinkWidget.tsx +0 -99
  246. package/src/widgets/components/ManyToManyWidget.tsx +0 -125
  247. package/src/widgets/components/ModalWidget.tsx +0 -52
  248. package/src/widgets/components/MoneyWidget.tsx +0 -80
  249. package/src/widgets/components/RepeatWidget.tsx +0 -66
  250. package/src/widgets/components/ScrollAreaWidget.tsx +0 -40
  251. package/src/widgets/components/SectionWidget.tsx +0 -78
  252. package/src/widgets/components/SelectWidget.tsx +0 -63
  253. package/src/widgets/components/SequenceWidget.tsx +0 -32
  254. package/src/widgets/components/SpacerWidget.tsx +0 -29
  255. package/src/widgets/components/SplitWidget.tsx +0 -60
  256. package/src/widgets/components/StackWidget.tsx +0 -44
  257. package/src/widgets/components/TableWidget.tsx +0 -366
  258. package/src/widgets/components/TextWidget.tsx +0 -44
  259. package/src/widgets/components/TextareaWidget.tsx +0 -49
  260. package/src/widgets/components/TreeWidget.tsx +0 -109
  261. package/src/widgets/components/index.ts +0 -30
  262. package/src/widgets/components/register.ts +0 -93
  263. package/src/widgets/components/table/CellRenderers.tsx +0 -83
  264. package/src/widgets/components/table/TablePagination.tsx +0 -45
  265. package/src/widgets/components/table/TableToolbar.tsx +0 -285
  266. package/src/widgets/components/table/filter-operators.ts +0 -134
  267. package/src/widgets/components/table/index.ts +0 -11
  268. package/src/widgets/condition/evaluator.ts +0 -57
  269. package/src/widgets/condition/index.ts +0 -1
  270. package/src/widgets/context/builder.ts +0 -99
  271. package/src/widgets/context/index.ts +0 -8
  272. package/src/widgets/context/types.ts +0 -37
  273. package/src/widgets/data/index.ts +0 -5
  274. package/src/widgets/data/useModelQuery.ts +0 -116
  275. package/src/widgets/data/useModelRecord.ts +0 -37
  276. package/src/widgets/expression/evaluator.ts +0 -100
  277. package/src/widgets/expression/functions.ts +0 -131
  278. package/src/widgets/expression/index.ts +0 -13
  279. package/src/widgets/expression/parser.ts +0 -229
  280. package/src/widgets/expression/types.ts +0 -45
  281. package/src/widgets/form/FormContext.ts +0 -29
  282. package/src/widgets/form/FormProvider.tsx +0 -84
  283. package/src/widgets/form/FormWidget.tsx +0 -42
  284. package/src/widgets/form/index.ts +0 -4
  285. package/src/widgets/form/useFormState.ts +0 -127
  286. package/src/widgets/form/useFormSubmit.ts +0 -90
  287. package/src/widgets/form/useFormValidation.ts +0 -62
  288. package/src/widgets/hooks/index.ts +0 -8
  289. package/src/widgets/hooks/useAction.ts +0 -83
  290. package/src/widgets/hooks/useBind.ts +0 -34
  291. package/src/widgets/hooks/useCondition.ts +0 -21
  292. package/src/widgets/hooks/useDataQuery.ts +0 -48
  293. package/src/widgets/hooks/useExpression.ts +0 -14
  294. package/src/widgets/hooks/usePageState.ts +0 -21
  295. package/src/widgets/hooks/useSurfaceContext.ts +0 -11
  296. package/src/widgets/hooks/useWidgetContext.ts +0 -14
  297. package/src/widgets/index.ts +0 -80
  298. package/src/widgets/lib/layout-props.ts +0 -135
  299. package/src/widgets/reactivity/index.ts +0 -11
  300. package/src/widgets/reactivity/tracker.ts +0 -139
  301. package/src/widgets/reactivity/variables.ts +0 -213
  302. package/src/widgets/registry.ts +0 -41
  303. package/src/widgets/renderer/SlotRenderer.tsx +0 -47
  304. package/src/widgets/renderer/WidgetRenderer.tsx +0 -191
  305. package/src/widgets/renderer/index.ts +0 -4
  306. package/src/widgets/shell/WidgetSlotRenderer.tsx +0 -73
  307. package/src/widgets/shell/index.ts +0 -4
  308. package/src/widgets/shell/useActionHandlers.ts +0 -170
  309. package/src/widgets/state/index.ts +0 -2
  310. package/src/widgets/state/store.ts +0 -96
  311. package/src/widgets/types.ts +0 -28
  312. package/src/widgets/validation/index.ts +0 -2
  313. package/src/widgets/validation/validator.ts +0 -140
  314. package/tsconfig.json +0 -27
  315. package/tsconfig.tsbuildinfo +0 -1
  316. package/vite.config.ts +0 -21
  317. package/vitest.config.ts +0 -16
@@ -1,38 +0,0 @@
1
- import type { ReactNode } from 'react';
2
-
3
- export interface AppSidebarModule {
4
- name: string;
5
- label: string;
6
- icon?: ReactNode;
7
- }
8
-
9
- export interface AppSidebarNavItem {
10
- title: string;
11
- url: string;
12
- }
13
-
14
- export interface AppSidebarNavSection {
15
- title: string;
16
- icon?: ReactNode;
17
- items: AppSidebarNavItem[];
18
- }
19
-
20
- export interface AppSidebarUser {
21
- name: string;
22
- email: string;
23
- avatar?: string;
24
- }
25
-
26
- export interface AppSidebarProps {
27
- modules: AppSidebarModule[];
28
- activeModule?: string;
29
- onModuleSwitch: (name: string) => void;
30
- onAllModules?: () => void;
31
- onSearch?: () => void;
32
- navigation: AppSidebarNavSection[];
33
- currentPath: string;
34
- onNavigate: (url: string) => void;
35
- user?: AppSidebarUser;
36
- onLogout?: () => void;
37
- onPreferences?: () => void;
38
- }
@@ -1,6 +0,0 @@
1
- export interface BreadcrumbItem {
2
- label: string;
3
- path?: string;
4
- }
5
-
6
- export type Size = 'sm' | 'md' | 'lg';
@@ -1,42 +0,0 @@
1
- import { useMemo } from 'react';
2
- import type { BreadcrumbItem } from './types.js';
3
- import type { NavigationTree, PageDefinition } from '@rangka/shared';
4
-
5
- export function useBreadcrumbs(
6
- currentPath: string,
7
- navigation: NavigationTree[],
8
- pages: PageDefinition[],
9
- ): BreadcrumbItem[] {
10
- return useMemo((): BreadcrumbItem[] => {
11
- const parts = currentPath.split('/').filter(Boolean);
12
- if (parts.length === 0) return [];
13
-
14
- const result: BreadcrumbItem[] = [];
15
-
16
- const moduleName = parts[0];
17
- const mod = navigation.find((n) => n.module === moduleName);
18
- if (mod) {
19
- result.push({
20
- label: mod.label,
21
- path: '/' + moduleName,
22
- });
23
- } else {
24
- result.push({ label: moduleName, path: '/' + moduleName });
25
- }
26
-
27
- if (parts.length >= 2) {
28
- const pageKey = `${parts[0]}.${parts[1]}`;
29
- const page = pages.find((p) => p.key === pageKey);
30
- result.push({
31
- label: page?.label ?? parts[1],
32
- path: '/' + parts.slice(0, 2).join('/'),
33
- });
34
- }
35
-
36
- if (parts.length >= 3) {
37
- result.push({ label: parts[2], path: currentPath });
38
- }
39
-
40
- return result;
41
- }, [currentPath, navigation, pages]);
42
- }
@@ -1,125 +0,0 @@
1
- import type { ClientToStudioMessage, StudioToClientMessage } from './types.js';
2
- import { findWidgetElement, buildWidgetPath, findPageKey, extractMeta } from './walker.js';
3
- import { createOverlay, updateOverlay, showOverlay, hideOverlay } from './overlay.js';
4
-
5
- export function initBridge(): void {
6
- if (window.parent === window) return;
7
-
8
- createOverlay();
9
- let inspecting = false;
10
-
11
- function startInspect() {
12
- inspecting = true;
13
- document.body.style.cursor = 'crosshair';
14
- }
15
-
16
- function stopInspect() {
17
- inspecting = false;
18
- hideOverlay();
19
- document.body.style.cursor = '';
20
- }
21
-
22
- // Expose for console debugging
23
- (window as unknown as Record<string, unknown>).__rangkaStudio = {
24
- startInspect,
25
- stopInspect,
26
- isInspecting: () => inspecting,
27
- };
28
-
29
- window.addEventListener('message', (event) => {
30
- const msg = event.data as StudioToClientMessage;
31
- if (!msg?.type?.startsWith('rangka-studio:')) return;
32
-
33
- if (msg.type === 'rangka-studio:inspect-start') {
34
- startInspect();
35
- } else if (msg.type === 'rangka-studio:inspect-stop') {
36
- stopInspect();
37
- } else if (msg.type === 'rangka-studio:pong') {
38
- if (msg.inspecting) {
39
- startInspect();
40
- }
41
- }
42
- });
43
-
44
- document.addEventListener('mousemove', (e) => {
45
- if (!inspecting) return;
46
- const target = e.target as HTMLElement;
47
- const widgetEl = findWidgetElement(target);
48
- if (widgetEl) {
49
- const rect = getMeasurableRect(widgetEl);
50
- updateOverlay(rect);
51
- showOverlay();
52
- const widgetPath = buildWidgetPath(widgetEl);
53
- const pageKey = findPageKey(widgetEl);
54
- post({
55
- type: 'rangka-client:hover',
56
- widgetPath,
57
- rect: { top: rect.top, left: rect.left, width: rect.width, height: rect.height },
58
- pageKey,
59
- });
60
- } else {
61
- hideOverlay();
62
- post({ type: 'rangka-client:hover-out' });
63
- }
64
- });
65
-
66
- document.addEventListener(
67
- 'click',
68
- (e) => {
69
- if (!inspecting) return;
70
- e.preventDefault();
71
- e.stopPropagation();
72
- const target = e.target as HTMLElement;
73
- const widgetEl = findWidgetElement(target);
74
- if (widgetEl) {
75
- const widgetPath = buildWidgetPath(widgetEl);
76
- const meta = extractMeta(widgetEl);
77
- const pageKey = findPageKey(widgetEl);
78
- post({ type: 'rangka-client:select', widgetPath, meta, pageKey });
79
- }
80
- },
81
- { capture: true },
82
- );
83
-
84
- patchNavigation();
85
-
86
- post({ type: 'rangka-client:ready' });
87
- post({ type: 'rangka-client:ping' });
88
- post({ type: 'rangka-client:navigate', path: window.location.pathname });
89
- }
90
-
91
- function patchNavigation(): void {
92
- const originalPushState = history.pushState.bind(history);
93
- const originalReplaceState = history.replaceState.bind(history);
94
-
95
- history.pushState = function (...args) {
96
- originalPushState(...args);
97
- notifyNavigation();
98
- };
99
-
100
- history.replaceState = function (...args) {
101
- originalReplaceState(...args);
102
- notifyNavigation();
103
- };
104
-
105
- window.addEventListener('popstate', () => {
106
- notifyNavigation();
107
- });
108
- }
109
-
110
- function notifyNavigation(): void {
111
- post({ type: 'rangka-client:navigate', path: window.location.pathname });
112
- }
113
-
114
- function post(msg: ClientToStudioMessage): void {
115
- window.parent.postMessage(msg, '*');
116
- }
117
-
118
- function getMeasurableRect(el: HTMLElement): DOMRect {
119
- const rect = el.getBoundingClientRect();
120
- if (rect.width > 0 && rect.height > 0) return rect;
121
- // display:contents elements have no box — measure first child instead
122
- const child = el.firstElementChild as HTMLElement | null;
123
- if (child) return child.getBoundingClientRect();
124
- return rect;
125
- }
@@ -1,3 +0,0 @@
1
- import { initBridge } from './bridge.js';
2
-
3
- initBridge();
@@ -1,47 +0,0 @@
1
- let overlay: HTMLElement | null = null;
2
-
3
- export function createOverlay(): HTMLElement {
4
- if (overlay) return overlay;
5
-
6
- overlay = document.createElement('div');
7
- overlay.id = 'rangka-studio-overlay';
8
- Object.assign(overlay.style, {
9
- position: 'fixed',
10
- pointerEvents: 'none',
11
- zIndex: '99999',
12
- border: '2px solid hsl(221 83% 53%)',
13
- background: 'hsl(221 83% 53% / 0.08)',
14
- borderRadius: '4px',
15
- display: 'none',
16
- });
17
- document.body.appendChild(overlay);
18
- return overlay;
19
- }
20
-
21
- export function updateOverlay(rect: {
22
- top: number;
23
- left: number;
24
- width: number;
25
- height: number;
26
- }): void {
27
- if (!overlay) return;
28
- overlay.style.top = `${rect.top}px`;
29
- overlay.style.left = `${rect.left}px`;
30
- overlay.style.width = `${rect.width}px`;
31
- overlay.style.height = `${rect.height}px`;
32
- }
33
-
34
- export function showOverlay(): void {
35
- if (overlay) overlay.style.display = 'block';
36
- }
37
-
38
- export function hideOverlay(): void {
39
- if (overlay) overlay.style.display = 'none';
40
- }
41
-
42
- export function destroyOverlay(): void {
43
- if (overlay) {
44
- overlay.remove();
45
- overlay = null;
46
- }
47
- }
@@ -1,32 +0,0 @@
1
- export type StudioToClientMessage =
2
- | { type: 'rangka-studio:inspect-start' }
3
- | { type: 'rangka-studio:inspect-stop' }
4
- | { type: 'rangka-studio:pong'; inspecting: boolean };
5
-
6
- export type ClientToStudioMessage =
7
- | { type: 'rangka-client:ready' }
8
- | { type: 'rangka-client:ping' }
9
- | { type: 'rangka-client:hover'; widgetPath: string[]; rect: WidgetRect; pageKey?: string }
10
- | { type: 'rangka-client:hover-out' }
11
- | {
12
- type: 'rangka-client:select';
13
- widgetPath: string[];
14
- meta: WidgetInspectMeta;
15
- pageKey?: string;
16
- }
17
- | { type: 'rangka-client:navigate'; path: string };
18
-
19
- export interface WidgetRect {
20
- top: number;
21
- left: number;
22
- width: number;
23
- height: number;
24
- }
25
-
26
- export interface WidgetInspectMeta {
27
- type: string;
28
- id?: string;
29
- model?: string;
30
- field?: string;
31
- mode?: string;
32
- }
@@ -1,48 +0,0 @@
1
- import type { WidgetInspectMeta } from './types.js';
2
-
3
- export function findWidgetElement(el: HTMLElement): HTMLElement | null {
4
- let current: HTMLElement | null = el;
5
- while (current) {
6
- if (current.hasAttribute('data-rangka-widget')) return current;
7
- current = current.parentElement;
8
- }
9
- return null;
10
- }
11
-
12
- export function buildWidgetPath(el: HTMLElement): string[] {
13
- const segments: string[] = [];
14
- let current: HTMLElement | null = el;
15
-
16
- while (current) {
17
- if (current.hasAttribute('data-rangka-widget')) {
18
- const id = current.getAttribute('data-rangka-id');
19
- const type = current.getAttribute('data-rangka-widget')!;
20
- segments.push(id || type);
21
- }
22
- current = current.parentElement;
23
- }
24
-
25
- segments.reverse();
26
- return segments;
27
- }
28
-
29
- export function findPageKey(el: HTMLElement): string | undefined {
30
- let current: HTMLElement | null = el;
31
- while (current) {
32
- if (current.hasAttribute('data-page-key')) {
33
- return current.getAttribute('data-page-key') ?? undefined;
34
- }
35
- current = current.parentElement;
36
- }
37
- return undefined;
38
- }
39
-
40
- export function extractMeta(el: HTMLElement): WidgetInspectMeta {
41
- return {
42
- type: el.getAttribute('data-rangka-widget') ?? '',
43
- id: el.getAttribute('data-rangka-id') ?? undefined,
44
- model: el.getAttribute('data-rangka-model') ?? undefined,
45
- field: el.getAttribute('data-rangka-field') ?? undefined,
46
- mode: el.getAttribute('data-rangka-mode') ?? undefined,
47
- };
48
- }
package/src/vite-env.d.ts DELETED
@@ -1 +0,0 @@
1
- /// <reference types="vite/client" />
@@ -1,281 +0,0 @@
1
- import { describe, test, expect, vi } from 'vitest';
2
- import { dispatch } from '../action/dispatcher.js';
3
- import { StateStore } from '../state/store.js';
4
- import { createRootContext } from '../context/builder.js';
5
- import type { ActionContext, ActionHandlers } from '../action/dispatcher.js';
6
-
7
- function makeActionCtx(record: Record<string, unknown> = {}): ActionContext {
8
- return {
9
- widgetContext: createRootContext(record, 'sales.order', 'edit'),
10
- state: new StateStore(),
11
- };
12
- }
13
-
14
- describe('Action Edge Cases', () => {
15
- describe('setValue edge cases', () => {
16
- test('sets $state with expression referencing record', async () => {
17
- const ctx = makeActionCtx({ total: 500 });
18
- await dispatch(
19
- { type: 'setValue', field: '$state.hasTotal', value: '{{total > 0}}' },
20
- ctx,
21
- {},
22
- );
23
- expect(ctx.state.get('hasTotal')).toBe(true);
24
- });
25
-
26
- test('sets literal boolean value without expression', async () => {
27
- const ctx = makeActionCtx();
28
- await dispatch({ type: 'setValue', field: '$state.loading', value: true }, ctx, {});
29
- expect(ctx.state.get('loading')).toBe(true);
30
- });
31
-
32
- test('sets literal null value', async () => {
33
- const sets: [string, unknown][] = [];
34
- const handlers: ActionHandlers = { setRecordValue: (f, v) => sets.push([f, v]) };
35
- await dispatch({ type: 'setValue', field: 'name', value: null }, makeActionCtx(), handlers);
36
- expect(sets).toEqual([['name', null]]);
37
- });
38
-
39
- test('sets literal number value', async () => {
40
- const sets: [string, unknown][] = [];
41
- const handlers: ActionHandlers = { setRecordValue: (f, v) => sets.push([f, v]) };
42
- await dispatch({ type: 'setValue', field: 'count', value: 0 }, makeActionCtx(), handlers);
43
- expect(sets).toEqual([['count', 0]]);
44
- });
45
-
46
- test('string without expression is literal', async () => {
47
- const sets: [string, unknown][] = [];
48
- const handlers: ActionHandlers = { setRecordValue: (f, v) => sets.push([f, v]) };
49
- await dispatch(
50
- { type: 'setValue', field: 'status', value: 'draft' },
51
- makeActionCtx(),
52
- handlers,
53
- );
54
- expect(sets).toEqual([['status', 'draft']]);
55
- });
56
- });
57
-
58
- describe('setValues edge cases', () => {
59
- test('mix of $state and record with expressions', async () => {
60
- const sets: [string, unknown][] = [];
61
- const handlers: ActionHandlers = { setRecordValue: (f, v) => sets.push([f, v]) };
62
- const ctx = makeActionCtx({ qty: 5, rate: 10 });
63
- await dispatch(
64
- {
65
- type: 'setValues',
66
- values: {
67
- total: '{{qty * rate}}',
68
- '$state.calculated': true,
69
- status: 'calculated',
70
- },
71
- },
72
- ctx,
73
- handlers,
74
- );
75
- expect(sets).toEqual([
76
- ['total', 50],
77
- ['status', 'calculated'],
78
- ]);
79
- expect(ctx.state.get('calculated')).toBe(true);
80
- });
81
-
82
- test('empty values object does nothing', async () => {
83
- const ctx = makeActionCtx();
84
- await dispatch({ type: 'setValues', values: {} }, ctx, {});
85
- expect(ctx.state.keys()).toEqual([]);
86
- });
87
- });
88
-
89
- describe('navigate edge cases', () => {
90
- test('static path without expression', async () => {
91
- const paths: string[] = [];
92
- const handlers: ActionHandlers = { navigate: (p) => paths.push(p) };
93
- await dispatch({ type: 'navigate', path: '/dashboard' }, makeActionCtx(), handlers);
94
- expect(paths).toEqual(['/dashboard']);
95
- });
96
-
97
- test('path with multiple expressions', async () => {
98
- const paths: string[] = [];
99
- const handlers: ActionHandlers = { navigate: (p) => paths.push(p) };
100
- const ctx = makeActionCtx({ module: 'sales', id: '42' });
101
- await dispatch({ type: 'navigate', path: '/{{module}}/orders/{{id}}' }, ctx, handlers);
102
- expect(paths).toEqual(['/sales/orders/42']);
103
- });
104
- });
105
-
106
- describe('service edge cases', () => {
107
- test('service with no params', async () => {
108
- const serviceCall = vi.fn().mockResolvedValue({});
109
- const handlers: ActionHandlers = { service: serviceCall, refreshSource: vi.fn() };
110
- await dispatch({ type: 'service', name: 'sales.refresh' }, makeActionCtx(), handlers);
111
- expect(serviceCall).toHaveBeenCalledWith('sales.refresh', {});
112
- });
113
-
114
- test('$response is available in nested onSuccess actions', async () => {
115
- const serviceCall = vi.fn().mockResolvedValue({ id: 'new-1', status: 'created' });
116
- const paths: string[] = [];
117
- const handlers: ActionHandlers = {
118
- service: serviceCall,
119
- navigate: (p) => paths.push(p),
120
- };
121
- await dispatch(
122
- {
123
- type: 'service',
124
- name: 'sales.create',
125
- onSuccess: { type: 'navigate', path: '/orders/{{$response.id}}' },
126
- },
127
- makeActionCtx(),
128
- handlers,
129
- );
130
- expect(paths).toEqual(['/orders/new-1']);
131
- });
132
-
133
- test('service failure without onError does not throw', async () => {
134
- const serviceCall = vi.fn().mockRejectedValue(new Error('fail'));
135
- const handlers: ActionHandlers = { service: serviceCall };
136
- await expect(
137
- dispatch({ type: 'service', name: 'sales.fail' }, makeActionCtx(), handlers),
138
- ).resolves.toBeUndefined();
139
- });
140
- });
141
-
142
- describe('sequence edge cases', () => {
143
- test('empty sequence does nothing', async () => {
144
- await expect(
145
- dispatch({ type: 'sequence', actions: [] }, makeActionCtx(), {}),
146
- ).resolves.toBeUndefined();
147
- });
148
-
149
- test('sequence of $state writes accumulates', async () => {
150
- const ctx = makeActionCtx();
151
- await dispatch(
152
- {
153
- type: 'sequence',
154
- actions: [
155
- { type: 'setValue', field: '$state.a', value: 1 },
156
- { type: 'setValue', field: '$state.b', value: 2 },
157
- { type: 'setValue', field: '$state.c', value: 3 },
158
- ],
159
- },
160
- ctx,
161
- {},
162
- );
163
- expect(ctx.state.get('a')).toBe(1);
164
- expect(ctx.state.get('b')).toBe(2);
165
- expect(ctx.state.get('c')).toBe(3);
166
- });
167
-
168
- test('later actions in sequence see earlier state changes', async () => {
169
- const ctx = makeActionCtx();
170
- await dispatch(
171
- {
172
- type: 'sequence',
173
- actions: [
174
- { type: 'setValue', field: '$state.step', value: 1 },
175
- {
176
- type: 'conditional',
177
- condition: { field: '$state.step', operator: 'eq', value: 1 },
178
- then: { type: 'setValue', field: '$state.result', value: 'step1-done' },
179
- },
180
- ],
181
- },
182
- ctx,
183
- {},
184
- );
185
- expect(ctx.state.get('result')).toBe('step1-done');
186
- });
187
- });
188
-
189
- describe('conditional edge cases', () => {
190
- test('conditional without else does nothing on false', async () => {
191
- const ctx = makeActionCtx({ status: 'submitted' });
192
- const sets: [string, unknown][] = [];
193
- const handlers: ActionHandlers = { setRecordValue: (f, v) => sets.push([f, v]) };
194
- await dispatch(
195
- {
196
- type: 'conditional',
197
- condition: { field: 'status', operator: 'eq', value: 'draft' },
198
- then: { type: 'setValue', field: 'x', value: 1 },
199
- },
200
- ctx,
201
- handlers,
202
- );
203
- expect(sets).toEqual([]);
204
- });
205
-
206
- test('nested conditionals', async () => {
207
- const ctx = makeActionCtx({ a: 1, b: 2 });
208
- await dispatch(
209
- {
210
- type: 'conditional',
211
- condition: { field: 'a', operator: 'eq', value: 1 },
212
- then: {
213
- type: 'conditional',
214
- condition: { field: 'b', operator: 'eq', value: 2 },
215
- then: { type: 'setValue', field: '$state.result', value: 'both' },
216
- else: { type: 'setValue', field: '$state.result', value: 'only-a' },
217
- },
218
- else: { type: 'setValue', field: '$state.result', value: 'neither' },
219
- },
220
- ctx,
221
- {},
222
- );
223
- expect(ctx.state.get('result')).toBe('both');
224
- });
225
- });
226
-
227
- describe('model action edge cases', () => {
228
- test('model.update with explicit model and id overrides context', async () => {
229
- const modelUpdate = vi.fn().mockResolvedValue({});
230
- const handlers: ActionHandlers = { modelUpdate };
231
- const ctx = makeActionCtx({ id: '1' });
232
- await dispatch(
233
- {
234
- type: 'model.update',
235
- model: 'other.model',
236
- id: '99',
237
- data: { name: 'test' },
238
- },
239
- ctx,
240
- handlers,
241
- );
242
- expect(modelUpdate).toHaveBeenCalledWith('other.model', '99', { name: 'test' });
243
- });
244
-
245
- test('model.delete with explicit id from expression', async () => {
246
- const modelDelete = vi.fn().mockResolvedValue(undefined);
247
- const handlers: ActionHandlers = { modelDelete };
248
- const ctx = makeActionCtx({ selectedId: '55' });
249
- await dispatch(
250
- {
251
- type: 'model.delete',
252
- model: 'sales.order',
253
- id: '{{selectedId}}',
254
- },
255
- ctx,
256
- handlers,
257
- );
258
- expect(modelDelete).toHaveBeenCalledWith('sales.order', '55');
259
- });
260
- });
261
-
262
- describe('handler missing gracefully', () => {
263
- test('navigate without handler does not throw', async () => {
264
- await expect(
265
- dispatch({ type: 'navigate', path: '/test' }, makeActionCtx(), {}),
266
- ).resolves.toBeUndefined();
267
- });
268
-
269
- test('refreshSource without handler does not throw', async () => {
270
- await expect(
271
- dispatch({ type: 'refreshSource' }, makeActionCtx(), {}),
272
- ).resolves.toBeUndefined();
273
- });
274
-
275
- test('service without handler does not throw', async () => {
276
- await expect(
277
- dispatch({ type: 'service', name: 'test' }, makeActionCtx(), {}),
278
- ).resolves.toBeUndefined();
279
- });
280
- });
281
- });