lecodes-cli 0.13.1 → 0.14.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.
- package/dist/index.js +182 -89
- package/package.json +3 -3
- package/runtime/sdk/compile/assetIconMacro.ts +6 -4
- package/runtime/sdk/inject.ts +1 -0
- package/runtime/sdk/ui/UI.ts +1 -1
- package/runtime/sdk/ui/UITabs.ts +65 -4
- package/runtime/sdk-types.json +1 -1
package/runtime/sdk/ui/UITabs.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { PagerElement, type UIPager } from "./UIPager"
|
|
2
|
-
import { ScreenElement,
|
|
2
|
+
import { ScreenElement, UIScreen } from "./UIScreen"
|
|
3
3
|
import { UIButton } from "./UIButton"
|
|
4
4
|
import { UIRow, UIColumn, type UIRow as UIRowType } from "./UIContainer"
|
|
5
5
|
import { UIText } from "./UIText"
|
|
6
6
|
import { UIImage, type ImageSource } from "./UIImage"
|
|
7
|
+
import type { UIChildArg } from "./UINode"
|
|
7
8
|
|
|
8
9
|
// UITabs — the standard bottom-tab shell, prewired: a UIScreen composing [ UIPager (flexGrow: 1),
|
|
9
10
|
// tab bar ]. Pure SDK composition over the pager — zero new ABI, works wherever UIPager does.
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// so a designed mockup and the built app render identically.
|
|
11
|
+
// `defineTabs` (below) is its design-stage twin (lecodes-design/tabbar-surface.md): the same keyed
|
|
12
|
+
// config without screens, mounted per-file with a literal tab id. They share the constants and bar
|
|
13
|
+
// geometry in this file, so a designed mockup and the built app render identically.
|
|
13
14
|
|
|
14
15
|
/** Active/inactive/bar colors ride the theme — one `theme({ primaryColor, mutedColor, tabbarBg })`
|
|
15
16
|
* call restyles the bar app-wide; the fallbacks keep an unthemed app looking right. */
|
|
@@ -173,3 +174,63 @@ export class TabsElement extends ScreenElement {
|
|
|
173
174
|
export function UITabs(tabs: Record<string, UITabDef>): UITabs {
|
|
174
175
|
return new TabsElement(tabs) as unknown as UITabs
|
|
175
176
|
}
|
|
177
|
+
|
|
178
|
+
// ---- defineTabs — the design-stage twin ---------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
/** A `defineTabs` tab: `label` + optional `icon` (an `assetIcon("lucide:…")` call — never a
|
|
181
|
+
* hand-written source object). `UITabDef` is this plus the tab's root `screen`. */
|
|
182
|
+
export type TabDef = Omit<UITabDef, "screen">
|
|
183
|
+
|
|
184
|
+
/** What `defineTabs` returns: the bar (mount it yourself when the screen owns its whole layout)
|
|
185
|
+
* and the standard screen shell around it. `active` must be a declared tab id, as a literal. */
|
|
186
|
+
export type TabsHandle<T extends Record<string, TabDef>> = {
|
|
187
|
+
/** Tab ids in declaration order. */
|
|
188
|
+
ids: (keyof T & string)[]
|
|
189
|
+
/** The bar alone — one button per tab, the `active` one highlighted. */
|
|
190
|
+
bar(active: keyof T & string): UIRowType
|
|
191
|
+
/** A screen sitting ON the bar: `[ padded content column, bar ]`. */
|
|
192
|
+
screen(active: keyof T & string, ...children: UIChildArg[]): UIScreen
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Declare a tab bar WITHOUT screens — the design-stage twin of {@link UITabs} (same keys, same
|
|
197
|
+
* `tab-<id>` button names, same theme variables), for mockups where every screen is its own file
|
|
198
|
+
* and mounts the bar with a literal tab id:
|
|
199
|
+
*
|
|
200
|
+
* ```ts
|
|
201
|
+
* export const mainTabs = defineTabs({
|
|
202
|
+
* home: { label: "Home", icon: assetIcon("lucide:house") },
|
|
203
|
+
* profile: { label: "Profile", icon: assetIcon("lucide:user") },
|
|
204
|
+
* })
|
|
205
|
+
* // in a screen file:
|
|
206
|
+
* export default () => mainTabs.screen("home", [ ...content ])
|
|
207
|
+
* ```
|
|
208
|
+
*
|
|
209
|
+
* Restyle through the theme — `theme({ primaryColor, mutedColor, tabbarBg, screenBg })` recolors
|
|
210
|
+
* every bar at once. The built app passes the same keys (plus each tab's root screen) to `UITabs`,
|
|
211
|
+
* which renders the identical bar interactively.
|
|
212
|
+
*/
|
|
213
|
+
export function defineTabs<T extends Record<string, TabDef>>(tabs: T): TabsHandle<T> {
|
|
214
|
+
const ids = Object.keys(tabs) as (keyof T & string)[]
|
|
215
|
+
|
|
216
|
+
const bar = (active: keyof T & string) =>
|
|
217
|
+
UIRow(ids.map((id) => {
|
|
218
|
+
const def = tabs[id]
|
|
219
|
+
const color = id === active ? ACTIVE : INACTIVE
|
|
220
|
+
return UIButton(
|
|
221
|
+
def.icon ? UIImage(def.icon).style({ width: 22, height: 22, tintColor: color }) : null,
|
|
222
|
+
UIText(def.label).style({ fontSize: 10, color }),
|
|
223
|
+
).style({ name: `tab-${id}`, flexDirection: "column", gap: 3, flex: 1, pt: 8, pb: 6 })
|
|
224
|
+
})).style({
|
|
225
|
+
name: "tabbar", bgColor: BAR_BG, pb: "comfort-bottom",
|
|
226
|
+
borderTopWidth: 1, borderTopColor: BAR_BORDER,
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
const screen = (active: keyof T & string, ...children: UIChildArg[]) =>
|
|
230
|
+
UIScreen(
|
|
231
|
+
UIColumn(...children).style({ flexGrow: 1, p: 16, pt: "safe-top" }),
|
|
232
|
+
bar(active),
|
|
233
|
+
).style({ bgColor: SCREEN_BG })
|
|
234
|
+
|
|
235
|
+
return { ids, bar, screen }
|
|
236
|
+
}
|