@lotics/cli 0.21.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -94,11 +94,13 @@ export function buildStarterTemplate(args) {
94
94
  noEmit: true,
95
95
  jsx: "react-jsx",
96
96
  strict: true,
97
- noUnusedLocals: true,
98
- noUnusedParameters: true,
99
97
  noFallthroughCasesInSwitch: true,
100
98
  },
99
+ // Restrict tsc to the project's own sources. tsgo follows
100
+ // transitive imports into node_modules — strict rules
101
+ // (noUnusedLocals etc.) would fire on @lotics/ui's source.
101
102
  include: ["src", ".lotics"],
103
+ exclude: ["node_modules"],
102
104
  }, null, 2) + "\n",
103
105
  },
104
106
  {
@@ -116,18 +118,35 @@ import react from "@vitejs/plugin-react";
116
118
  // (View, Text, Pressable, StyleSheet, etc.) render in a pure-web environment.
117
119
  // .web.tsx is prioritized in resolve.extensions so per-target variants
118
120
  // (avatar.web.tsx, wave_avatar.web.tsx) win over the native .tsx file.
121
+ //
122
+ // @lotics/ui/icon.tsx imports from \`lucide-react-native/dist/esm/icons/<name>\`
123
+ // — deep paths that lucide-react-native's package \`exports\` map blocks under
124
+ // Vite's strict resolution. lucide-react has the same per-icon files with no
125
+ // exports map, so we alias the deep path to use it. Web rendering of <svg>
126
+ // is identical to RN-SVG when running under RN-Web.
119
127
  export default defineConfig({
120
128
  plugins: [react()],
121
129
  resolve: {
122
- alias: {
123
- "react-native": "react-native-web",
124
- },
130
+ alias: [
131
+ {
132
+ find: /^lucide-react-native\\/dist\\/esm\\/icons\\/(.+)$/,
133
+ replacement: "lucide-react/dist/esm/icons/$1",
134
+ },
135
+ { find: "react-native", replacement: "react-native-web" },
136
+ ],
125
137
  extensions: [".web.tsx", ".web.ts", ".tsx", ".ts", ".jsx", ".js"],
126
138
  },
127
139
  build: {
128
140
  outDir: "dist",
129
141
  sourcemap: true,
130
142
  },
143
+ server: {
144
+ // Allow the sandboxed null-origin iframe used by \`lotics app dev\` to
145
+ // fetch HMR client + source modules from the dev server. Production
146
+ // iframe loads modules from api.lotics.ai which already permits null
147
+ // origin via CORS.
148
+ cors: { origin: "*" },
149
+ },
131
150
  test: {
132
151
  environment: "jsdom",
133
152
  },
@@ -142,6 +161,20 @@ export default defineConfig({
142
161
  <meta charset="UTF-8" />
143
162
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
144
163
  <title>${escapeHtml(args.app_name)}</title>
164
+ <style>
165
+ /*
166
+ * Full-viewport container chain for iframe apps. @lotics/ui's DataGrid
167
+ * (and any layout that uses \`flex: 1\` to fill available space) relies
168
+ * on a measured parent height. The browser default of html/body being
169
+ * content-sized collapses every \`flex: 1\` to 0 and the surface shrinks
170
+ * to fit only its rendered content.
171
+ *
172
+ * Also: #root is made a flex column so the outermost RN \`<View flex:1>\`
173
+ * inside App.tsx claims the full iframe height.
174
+ */
175
+ html, body, #root { height: 100%; margin: 0; }
176
+ #root { display: flex; flex-direction: column; }
177
+ </style>
145
178
  </head>
146
179
  <body>
147
180
  <div id="root"></div>
@@ -161,37 +194,129 @@ mount(<App />);
161
194
  },
162
195
  {
163
196
  path: "src/App.tsx",
164
- // Static welcome screen using @lotics/ui primitives no useTable call
165
- // so the freshly-deployed v1 renders cleanly without needing a real
166
- // table id. The user's first edit is to replace this with their app.
197
+ // Welcome screen demonstrates the full-container layout pattern that
198
+ // real apps (data grids, dashboards, full-page surfaces) rely on:
199
+ // - Outer <View flex:1> claims the full iframe height (works because
200
+ // index.html sets html/body/#root to 100% + #root is a flex column).
201
+ // - Inner View is content-sized + centered for a card layout.
202
+ //
203
+ // We deliberately do NOT use @lotics/ui/stack for the outer chain.
204
+ // Stack wraps each child in an unstyled <View>, which breaks `flex: 1`
205
+ // propagation to children that need to claim flexible height (e.g., a
206
+ // DataGrid that fills the remaining space below a header + search).
207
+ // Use plain <View> with `flexDirection` + `gap` for any outer layout
208
+ // that hosts a flex-filling child; Stack is fine for content-sized
209
+ // groupings inside such a chain.
167
210
  content: `import { View } from "react-native";
168
- import { Stack } from "@lotics/ui/stack";
169
211
  import { Card } from "@lotics/ui/card";
170
212
  import { Text } from "@lotics/ui/text";
171
213
  import { Button } from "@lotics/ui/button";
172
214
 
215
+ // Outer <View flex:1> claims the full iframe height — works because
216
+ // index.html sets html/body/#root to 100% and #root is a flex column.
217
+ // For real layouts with a fill-remaining-space child (DataGrid etc.),
218
+ // keep this flex chain plain — @lotics/ui/stack wraps each child in an
219
+ // unstyled <View> that breaks \`flex: 1\` propagation.
173
220
  export default function App() {
174
221
  return (
175
- <View style={{ padding: 24, maxWidth: 640, marginHorizontal: "auto" }}>
176
- <Stack gap={16}>
222
+ <View
223
+ style={{
224
+ flex: 1,
225
+ padding: 24,
226
+ justifyContent: "center",
227
+ alignItems: "center",
228
+ }}
229
+ >
230
+ <View style={{ maxWidth: 640, width: "100%", gap: 16 }}>
177
231
  <Text size="xl" weight="semibold">${escapeHtml(args.app_name)}</Text>
178
232
  <Card>
179
- <Stack gap={8} style={{ padding: 16 }}>
233
+ <View style={{ padding: 16, gap: 8 }}>
180
234
  <Text>This is your new Lotics app.</Text>
181
235
  <Text color="muted">
182
236
  Edit <Text weight="medium">src/App.tsx</Text> and run{" "}
183
237
  <Text weight="medium">lotics app deploy</Text> to publish.
184
238
  </Text>
185
- </Stack>
239
+ </View>
186
240
  </Card>
187
241
  <Text color="muted" size="sm">
188
242
  Hooks from @lotics/app-sdk: useTable, useMutate, useAction, useQuery, useWorkflow.
189
243
  </Text>
190
244
  <Button title="Get started" onPress={() => {}} color="primary" />
191
- </Stack>
245
+ </View>
192
246
  </View>
193
247
  );
194
248
  }
249
+ `,
250
+ },
251
+ {
252
+ path: "src/lucide-react-native.d.ts",
253
+ content: `// Type shim for lucide-react-native's deep-icon imports
254
+ // (\`lucide-react-native/dist/esm/icons/<name>\`). The package ships JS-only
255
+ // files without per-file .d.ts. The Vite alias in vite.config.ts rewrites
256
+ // these to lucide-react at bundle time; this declaration covers the
257
+ // TypeScript compile-time gap.
258
+ declare module "lucide-react-native/dist/esm/icons/*" {
259
+ import type { ComponentType } from "react";
260
+ const Icon: ComponentType<{
261
+ size: number;
262
+ color: string;
263
+ fill?: string;
264
+ strokeWidth?: number;
265
+ }>;
266
+ export default Icon;
267
+ }
268
+ `,
269
+ },
270
+ {
271
+ path: "src/css_modules.d.ts",
272
+ content: `declare module "*.module.css" {
273
+ const classes: { [key: string]: string };
274
+ export default classes;
275
+ }
276
+ `,
277
+ },
278
+ {
279
+ path: "src/react_native.d.ts",
280
+ content: `import "react-native";
281
+
282
+ // Augments react-native's types with the web-only fields @lotics/ui consumes:
283
+ // Pressable's \`hovered\` callback state, plus web-only ViewStyle / TextStyle
284
+ // properties (cursor, outline, boxShadow, etc.) used by the grid + primitives.
285
+ // Each iframe app needs its own copy — TypeScript doesn't auto-pick-up
286
+ // \`.d.ts\` files inside dependencies. \`@lotics/ui\`'s grid sources include a
287
+ // triple-slash reference to its own copy of this file so the augmentation
288
+ // kicks in transitively.
289
+ declare module "react-native" {
290
+ interface PressableStateCallbackType {
291
+ hovered: boolean;
292
+ }
293
+
294
+ interface ViewStyle {
295
+ backdropFilter?: string;
296
+ backgroundImage?: string;
297
+ boxShadow?: string;
298
+ boxSizing?: string;
299
+ cursor?: string;
300
+ touchAction?: string;
301
+ transitionDuration?: string;
302
+ transitionProperty?: string;
303
+ appearance?: string;
304
+ outline?: string;
305
+ outlineColor?: string;
306
+ outlineStyle?: string;
307
+ outlineWidth?: number;
308
+ outlineOffset?: number;
309
+ }
310
+
311
+ interface TextStyle {
312
+ outline?: string;
313
+ outlineColor?: string;
314
+ outlineStyle?: string;
315
+ outlineWidth?: number;
316
+ outlineOffset?: number;
317
+ appearance?: string;
318
+ }
319
+ }
195
320
  `,
196
321
  },
197
322
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {