delacour 0.1.0-alpha.1 → 0.1.0-alpha.2
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/README.md +10 -3
- package/dist/index.js +78 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,15 +121,22 @@ never written to it.
|
|
|
121
121
|
|
|
122
122
|
## After `init`
|
|
123
123
|
|
|
124
|
-
Three things need a human, because each is a decision inside a file you own
|
|
124
|
+
Three things need a human, because each is a decision inside a file you own. `init` copies the
|
|
125
|
+
`provider` item in alongside `styles`, so the root every pressable needs is one import away — but
|
|
126
|
+
mounting it is an edit to your layout, and that stays yours:
|
|
125
127
|
|
|
126
128
|
```tsx
|
|
127
129
|
// app/_layout.tsx
|
|
128
130
|
import "@/styles/global.css";
|
|
129
|
-
import {
|
|
131
|
+
import { DelacourProvider } from "@/components/ui/provider";
|
|
132
|
+
import { Stack } from "expo-router";
|
|
130
133
|
|
|
131
134
|
export default function RootLayout() {
|
|
132
|
-
return
|
|
135
|
+
return (
|
|
136
|
+
<DelacourProvider>
|
|
137
|
+
<Stack />
|
|
138
|
+
</DelacourProvider>
|
|
139
|
+
);
|
|
133
140
|
}
|
|
134
141
|
```
|
|
135
142
|
|
package/dist/index.js
CHANGED
|
@@ -9943,13 +9943,13 @@ const DEFAULT_REGISTRY_URL = "https://raw.githubusercontent.com/delacournz/delac
|
|
|
9943
9943
|
* Replaced at build time with the git tag being published (see `tsdown.config.ts`).
|
|
9944
9944
|
* `main` in a working tree, where there is no tag yet.
|
|
9945
9945
|
*/
|
|
9946
|
-
const DEFAULT_REGISTRY_REF = "
|
|
9946
|
+
const DEFAULT_REGISTRY_REF = "10f3730f22e550ce8327ff388dacf6191975fda8";
|
|
9947
9947
|
const RAW_GITHUB = "https://raw.githubusercontent.com";
|
|
9948
9948
|
const GITHUB_SHORTHAND = /^github:([^/#]+)\/([^/#]+)(?:#(.+))?$/;
|
|
9949
9949
|
/** `https://raw.githubusercontent.com/owner/repo` and nothing more. */
|
|
9950
9950
|
const BARE_RAW_REPO = new RegExp(`^${RAW_GITHUB}/([^/]+)/([^/]+)$`);
|
|
9951
9951
|
function resolveRegistrySource(options) {
|
|
9952
|
-
const ref = options.ref || "
|
|
9952
|
+
const ref = options.ref || "10f3730f22e550ce8327ff388dacf6191975fda8";
|
|
9953
9953
|
const url = options.url?.trim();
|
|
9954
9954
|
if (!url) return remote(`${DEFAULT_REGISTRY_URL}/${ref}`);
|
|
9955
9955
|
const shorthand = GITHUB_SHORTHAND.exec(url);
|
|
@@ -12128,23 +12128,40 @@ function matchesEntry(imported, target) {
|
|
|
12128
12128
|
* Every pressable in the library is a Gesture Handler detector, and a detector
|
|
12129
12129
|
* outside a `GestureHandlerRootView` never receives a touch. Nothing throws;
|
|
12130
12130
|
* the button simply does not respond.
|
|
12131
|
+
*
|
|
12132
|
+
* `DelacourProvider` is that root, plus the other layers, so mounting it
|
|
12133
|
+
* counts. The copied components are skipped on purpose: `provider.tsx` itself
|
|
12134
|
+
* names both, and `init` copies it into every project, so a walk that read it
|
|
12135
|
+
* would pass an app that never mounted anything. The app root is read one level
|
|
12136
|
+
* deep as well as the usual `app/` and `src/` walks, because a blank Expo
|
|
12137
|
+
* template mounts everything from `App.tsx` at the top.
|
|
12138
|
+
*
|
|
12139
|
+
* Exported for the tests; `runChecks` is the entry point.
|
|
12131
12140
|
*/
|
|
12132
12141
|
async function checkGestureHandlerRoot(config) {
|
|
12142
|
+
const appRoot = config.app.resolved.root;
|
|
12143
|
+
const skip = Object.values(config.directories);
|
|
12133
12144
|
const roots = [
|
|
12134
12145
|
"src/app",
|
|
12135
12146
|
"app",
|
|
12136
12147
|
"src"
|
|
12137
|
-
].map((path) => join(
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12148
|
+
].map((path) => join(appRoot, path));
|
|
12149
|
+
for (const needle of ["DelacourProvider", "GestureHandlerRootView"]) {
|
|
12150
|
+
const walked = await Promise.all(roots.map((root) => containsText(root, needle, { skip })));
|
|
12151
|
+
if (await containsText(appRoot, needle, {
|
|
12152
|
+
skip,
|
|
12153
|
+
recursive: false
|
|
12154
|
+
}) || walked.some(Boolean)) return {
|
|
12155
|
+
name: "Gesture Handler",
|
|
12156
|
+
status: "pass",
|
|
12157
|
+
detail: `${needle} found at the app root`
|
|
12158
|
+
};
|
|
12159
|
+
}
|
|
12143
12160
|
return {
|
|
12144
12161
|
name: "Gesture Handler",
|
|
12145
12162
|
status: "warn",
|
|
12146
|
-
detail: "no GestureHandlerRootView found",
|
|
12147
|
-
fix: "Wrap your root layout in <GestureHandlerRootView style={{ flex: 1 }}
|
|
12163
|
+
detail: "no DelacourProvider or GestureHandlerRootView found",
|
|
12164
|
+
fix: "Wrap your root layout in <DelacourProvider> from your ui directory — or, by hand, <GestureHandlerRootView style={{ flex: 1 }}>. Presses do nothing without one of them."
|
|
12148
12165
|
};
|
|
12149
12166
|
}
|
|
12150
12167
|
/**
|
|
@@ -12203,16 +12220,18 @@ async function readExpoConfig(cwd) {
|
|
|
12203
12220
|
return null;
|
|
12204
12221
|
}
|
|
12205
12222
|
}
|
|
12206
|
-
async function containsText(directory, needle) {
|
|
12223
|
+
async function containsText(directory, needle, options = {}) {
|
|
12207
12224
|
let entries;
|
|
12208
12225
|
try {
|
|
12209
|
-
entries = await readdir(directory, { recursive: true });
|
|
12226
|
+
entries = await readdir(directory, { recursive: options.recursive ?? true });
|
|
12210
12227
|
} catch {
|
|
12211
12228
|
return false;
|
|
12212
12229
|
}
|
|
12213
12230
|
for (const entry of entries) {
|
|
12214
|
-
if (!/\.tsx?$/.test(entry)) continue;
|
|
12215
|
-
|
|
12231
|
+
if (!/\.tsx?$/.test(entry) || entry.includes("node_modules")) continue;
|
|
12232
|
+
const path = join(directory, entry);
|
|
12233
|
+
if (options.skip?.some((skipped) => path === skipped || path.startsWith(`${skipped}/`))) continue;
|
|
12234
|
+
if ((await read$1(path))?.includes(needle)) return true;
|
|
12216
12235
|
}
|
|
12217
12236
|
return false;
|
|
12218
12237
|
}
|
|
@@ -12341,6 +12360,7 @@ function toPosix$1(path) {
|
|
|
12341
12360
|
//#region src/commands/init.ts
|
|
12342
12361
|
var init_exports = /* @__PURE__ */ __exportAll({
|
|
12343
12362
|
defaultPlacement: () => defaultPlacement,
|
|
12363
|
+
followUps: () => followUps,
|
|
12344
12364
|
init: () => init
|
|
12345
12365
|
});
|
|
12346
12366
|
async function init(components, options) {
|
|
@@ -12366,7 +12386,11 @@ async function init(components, options) {
|
|
|
12366
12386
|
packageName: placement.packageName
|
|
12367
12387
|
}), placement.root, output);
|
|
12368
12388
|
await wireUpApp(resolved, resolved.package ? project.workspaceRoot : null, output);
|
|
12369
|
-
await add([
|
|
12389
|
+
await add([
|
|
12390
|
+
"styles",
|
|
12391
|
+
"provider",
|
|
12392
|
+
...components
|
|
12393
|
+
], {
|
|
12370
12394
|
...options,
|
|
12371
12395
|
cwd: placement.root,
|
|
12372
12396
|
overwrite: true
|
|
@@ -12509,6 +12533,7 @@ async function wireUpApp(config, workspaceRoot, output) {
|
|
|
12509
12533
|
metro.snippet
|
|
12510
12534
|
].join("\n"));
|
|
12511
12535
|
await ensureUniwindEnv(config, output);
|
|
12536
|
+
await ensureExpoEnv(config, output);
|
|
12512
12537
|
const block = buildStylesBlock({
|
|
12513
12538
|
cssPath: config.app.resolved.css,
|
|
12514
12539
|
directories: config.directories
|
|
@@ -12540,6 +12565,25 @@ async function ensureUniwindEnv(config, output) {
|
|
|
12540
12565
|
output.success(`Wrote ${style.path("uniwind-env.d.ts")} — the app needs it too, not just the package`);
|
|
12541
12566
|
}
|
|
12542
12567
|
/**
|
|
12568
|
+
* The file Expo's own CLI writes on first `start`, and nothing before that.
|
|
12569
|
+
*
|
|
12570
|
+
* `expo/types` is what declares `*.css` as a module. A template without a
|
|
12571
|
+
* router — `blank-typescript` — ships no `expo-env.d.ts`, so the CSS import
|
|
12572
|
+
* `init` just asked for fails `tsc` with "Cannot find module … './styles/global.css'"
|
|
12573
|
+
* until the app has been started once. Metro is fine either way; only the
|
|
12574
|
+
* typecheck a reader runs first is not.
|
|
12575
|
+
*/
|
|
12576
|
+
async function ensureExpoEnv(config, output) {
|
|
12577
|
+
if (config.framework !== "expo") return;
|
|
12578
|
+
const path = join(config.app.resolved.root, "expo-env.d.ts");
|
|
12579
|
+
if (existsSync(path)) return;
|
|
12580
|
+
await write$1(path, `${EXPO_ENV_REFERENCE}\n`);
|
|
12581
|
+
output.success(`Wrote ${style.path("expo-env.d.ts")} — it declares *.css as a module`);
|
|
12582
|
+
}
|
|
12583
|
+
const EXPO_ENV_REFERENCE = `/// <reference types="expo/types" />
|
|
12584
|
+
|
|
12585
|
+
// NOTE: This file should not be edited and should be in your git ignore`;
|
|
12586
|
+
/**
|
|
12543
12587
|
* What is left, and why the CLI did not just do it.
|
|
12544
12588
|
*
|
|
12545
12589
|
* Each of these needs a decision or an AST edit inside a file the project owns.
|
|
@@ -12547,18 +12591,30 @@ async function ensureUniwindEnv(config, output) {
|
|
|
12547
12591
|
* the only chance to see it.
|
|
12548
12592
|
*/
|
|
12549
12593
|
function printFollowUps(config, output) {
|
|
12550
|
-
const items = [];
|
|
12551
|
-
if (Object.keys(config.aliases).length > 0) items.push(`Set ${style.code("experiments.tsconfigPaths: true")} in app.config — Metro ignores tsconfig paths without it.`);
|
|
12552
|
-
items.push(`Import ${style.code(`"${config.aliases.styles ?? "."}/${basename(config.app.resolved.css)}"`)} as the first statement of your root layout — without it every component renders unstyled.`);
|
|
12553
|
-
items.push(`Wrap the app root in ${style.code("<GestureHandlerRootView style={{ flex: 1 }}>")} — presses do nothing without it.`);
|
|
12554
|
-
items.push(`${style.code("theme.css")} is the file to edit — replace it with the theme.css tab from https://ui.delacour.co.nz/theme, or paste a shadcn or tweakcn globals.css over it and run ${style.code("delacour theme")}.`);
|
|
12555
12594
|
output.info([
|
|
12556
12595
|
`A few things need you:`,
|
|
12557
|
-
...
|
|
12596
|
+
...followUps(config).map((line) => ` • ${line}`),
|
|
12558
12597
|
"",
|
|
12559
12598
|
`Run ${style.code("delacour doctor")} to check.`
|
|
12560
12599
|
].join("\n"));
|
|
12561
12600
|
}
|
|
12601
|
+
/**
|
|
12602
|
+
* The follow-up lines themselves, in the order they are printed.
|
|
12603
|
+
*
|
|
12604
|
+
* Exported so the order is testable: the CSS import goes first because it is
|
|
12605
|
+
* the only one of these that produces no error at all, and the provider before
|
|
12606
|
+
* the theme because a theme is a choice and a root that receives touches is not.
|
|
12607
|
+
*/
|
|
12608
|
+
function followUps(config) {
|
|
12609
|
+
const items = [];
|
|
12610
|
+
if (Object.keys(config.aliases).length > 0) items.push(`Set ${style.code("experiments.tsconfigPaths: true")} in app.config — Metro ignores tsconfig paths without it.`);
|
|
12611
|
+
const cssImport = config.aliases.styles ? `${config.aliases.styles}/${basename(config.app.resolved.css)}` : `./${short(config.app.resolved.root, config.app.resolved.css)}`;
|
|
12612
|
+
items.push(`Import ${style.code(`"${cssImport}"`)} as the first statement of your root layout — without it every component renders unstyled.`);
|
|
12613
|
+
const providerImport = `${config.aliases.ui ?? `./${short(config.app.resolved.root, config.directories.ui)}`}/provider`;
|
|
12614
|
+
items.push(`Wrap the app root in ${style.code("<DelacourProvider>")} from ${style.code(`"${providerImport}"`)} — presses do nothing without it.`);
|
|
12615
|
+
items.push(`${style.code("theme.css")} is the file to edit — replace it with the theme.css tab from https://ui.delacour.co.nz/theme, or paste a shadcn or tweakcn globals.css over it and run ${style.code("delacour theme")}.`);
|
|
12616
|
+
return items;
|
|
12617
|
+
}
|
|
12562
12618
|
function warnAboutStack(project, output) {
|
|
12563
12619
|
if (!project.packageJson) {
|
|
12564
12620
|
output.warn("No package.json here. Run this inside your Expo app.");
|
|
@@ -28411,7 +28467,7 @@ function report(result, output) {
|
|
|
28411
28467
|
}
|
|
28412
28468
|
//#endregion
|
|
28413
28469
|
//#region src/index.ts
|
|
28414
|
-
const program = new Command().name("delacour").description("Add React Native components to your Expo app. You own the code.").version("0.1.0-alpha.
|
|
28470
|
+
const program = new Command().name("delacour").description("Add React Native components to your Expo app. You own the code.").version("0.1.0-alpha.2");
|
|
28415
28471
|
/** Shared by every command that reads the registry. */
|
|
28416
28472
|
function withRegistryOptions(command) {
|
|
28417
28473
|
return command.addOption(new Option("--registry <url>", "registry to read from: a URL, github:owner/repo, or a local path")).addOption(new Option("--ref <ref>", "git ref to read the registry at").default(DEFAULT_REGISTRY_REF)).addOption(new Option("--offline", "use only what is already cached")).addOption(new Option("-c, --cwd <path>", "directory to work in").default(process.cwd()));
|