@lyda/kilo-ui 0.1.1 → 0.1.5

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 CHANGED
@@ -12,12 +12,13 @@ After you **publish** this project to npm, install the **exact** `name` from its
12
12
  **Do not** run `npm install -D kilo-ui` expecting this Vue CLI — the public npm name `kilo-ui` is already used by a different project.
13
13
 
14
14
  ```bash
15
- npm install -D @lyda/kilo-ui
16
- npx kilo-ui init
15
+ npm install -D @lyda/kilo-ui@latest
17
16
  npx kilo-ui add data-table
18
17
  ```
19
18
 
20
- If the package was published with an installer hook, `npm install -D ...` will run `kilo-ui init` automatically once. If you use `--ignore-scripts`, run `npx kilo-ui init` manually.
19
+ **First install in a new project:** the package **postinstall** runs `kilo-ui init` once (unless `kilo.config.ts` already exists). That creates **`kilo.config.ts` in your app root** (next to `package.json`) — not inside `node_modules`. Edit **`ui.componentsDir`** (or **`componentsPrefix`**) for the install folder (e.g. `ki` `src/components/ki/...`). If the folder is not `ui`, **`kilo-ui add`** injects **`defineOptions({ name: "KiCardBox" })`** so you can use **`<KiCardBox />`** (prefix + file name). Use **`ui.componentTagPrefix: false`** to skip that. An annotated example ships at **`node_modules/@lyda/kilo-ui/config/kilo.config.example.ts`**. If install used **`--ignore-scripts`**, run **`npx kilo-ui init`** once yourself.
20
+
21
+ You can still run **`npx kilo-ui init`** anytime to add missing scaffold files; use **`init --force`** to reset **`kilo.config.ts`** to defaults (back up first if you customized it).
21
22
 
22
23
  **Note:** The public npm name `kilo-ui` may point to a different project (not this Vue CLI). If `npm install -D kilo-ui` pulls SvelteKit or other wrong peers, use a scoped name or install from `file:` / Git. See [Installation](docs/docs/installation.md) in the docs site.
23
24
 
@@ -25,9 +26,10 @@ If the package was published with an installer hook, `npm install -D ...` will r
25
26
 
26
27
  `npx kilo-ui init` creates:
27
28
 
28
- - `components.json` - config and aliases
29
+ - **`kilo.config.ts`** - TypeScript project config (`defineConfig` from `@lyda/kilo-ui/config`), aliases, and **`ui.componentsDir`** (subfolder for installed components, default `ui`)
29
30
  - `src/styles/teamwork-ui.css` - Tailwind v4 import + Kilo UI theme tokens
30
31
  - `src/lib/utils.ts` - shared helper utilities
32
+ - `env.d.ts` (project root) - Vue + Vite TypeScript declarations for `*.vue` modules (skip if the file already exists); `init` also updates `tsconfig.app.json` / `tsconfig.json` with `paths` for `@/*` when possible
31
33
 
32
34
  Add the stylesheet once in your app entry, usually `src/main.ts`:
33
35
 
package/bin/kilo-ui.mjs CHANGED
@@ -1,20 +1,30 @@
1
1
  #!/usr/bin/env node
2
+ import { createJiti } from 'jiti'
2
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
3
- import { dirname, join, relative, resolve } from 'node:path'
4
+ import { basename, dirname, join, relative, resolve } from 'node:path'
4
5
  import { fileURLToPath } from 'node:url'
5
6
 
6
7
  const __dirname = dirname(fileURLToPath(import.meta.url))
7
8
  const packageRoot = resolve(__dirname, '..')
8
9
  const registryRoot = join(packageRoot, 'registry')
10
+ const cliEntry = fileURLToPath(import.meta.url)
9
11
 
10
12
  const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))
11
13
  const cliName = typeof pkg.name === 'string' ? pkg.name : 'kilo-ui'
14
+ const pkgName = cliName
12
15
 
13
16
  const commands = new Set(['init', 'add', 'list', 'help'])
14
17
  const [, , maybeCommand, ...args] = process.argv
15
18
  const command = commands.has(maybeCommand) ? maybeCommand : 'help'
16
19
 
17
- const configFile = 'components.json'
20
+ const KILO_TS = 'kilo.config.ts'
21
+ const KILO_MTS = 'kilo.config.mts'
22
+ const KILO_JS = 'kilo.config.js'
23
+ const KILO_MJS = 'kilo.config.mjs'
24
+ const CONFIG_MODULES = [KILO_TS, KILO_MTS, KILO_JS, KILO_MJS]
25
+
26
+ const UI_JSON = 'ui.json'
27
+ const LEGACY_JSON = 'components.json'
18
28
 
19
29
  function log(message = '') {
20
30
  console.log(message)
@@ -26,7 +36,8 @@ function fail(message) {
26
36
  }
27
37
 
28
38
  function readJson(path) {
29
- return JSON.parse(readFileSync(path, 'utf8'))
39
+ const raw = readFileSync(path, 'utf8').replace(/^\uFEFF/, '')
40
+ return JSON.parse(raw)
30
41
  }
31
42
 
32
43
  function writeJson(path, value) {
@@ -51,17 +62,121 @@ function registry() {
51
62
  return readJson(join(registryRoot, 'index.json'))
52
63
  }
53
64
 
65
+ const defaultAliases = {
66
+ components: '@/components',
67
+ composables: '@/composables',
68
+ lib: '@/lib',
69
+ types: '@/types',
70
+ }
71
+
72
+ function normalizeConfig(raw) {
73
+ const c = typeof raw === 'object' && raw !== null ? { ...raw } : {}
74
+ c.srcDir = c.srcDir || 'src'
75
+ c.aliases = { ...defaultAliases, ...(c.aliases || {}) }
76
+ c.tailwind = c.tailwind || { css: `${c.srcDir}/styles/teamwork-ui.css` }
77
+ const uiRaw =
78
+ typeof c.ui === 'object' && c.ui !== null ? { ...c.ui } : {}
79
+ const componentsPrefix = uiRaw.componentsPrefix
80
+ delete uiRaw.componentsPrefix
81
+ c.ui = { componentsDir: 'ui', ...uiRaw }
82
+ if (
83
+ (c.ui.componentsDir === undefined || c.ui.componentsDir === null) &&
84
+ componentsPrefix !== undefined &&
85
+ componentsPrefix !== null
86
+ ) {
87
+ c.ui.componentsDir = componentsPrefix
88
+ }
89
+ if (c.ui.componentsDir === undefined || c.ui.componentsDir === null) {
90
+ c.ui.componentsDir = 'ui'
91
+ }
92
+ return c
93
+ }
94
+
95
+ /** "ki" → "Ki", "my-kit" → "MyKit" */
96
+ function segmentToPascal(segment) {
97
+ return String(segment)
98
+ .split(/[^a-zA-Z0-9]+/)
99
+ .filter(Boolean)
100
+ .map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())
101
+ .join('')
102
+ }
103
+
104
+ /** Pascal prefix for defineOptions name, or null if disabled / default ui folder. */
105
+ function effectiveDevTagPrefix(config) {
106
+ const v = config.ui?.componentTagPrefix
107
+ if (v === false) return null
108
+ if (typeof v === 'string' && v.trim().length) return segmentToPascal(v.trim())
109
+
110
+ const segs = componentDirSegments(config)
111
+ const first = segs[0]
112
+ if (!first) return null
113
+ if (first.toLowerCase() === 'ui') return null
114
+ return segmentToPascal(first)
115
+ }
116
+
117
+ function vueResolvedComponentName(config, fileBaseNoExt) {
118
+ const prefix = effectiveDevTagPrefix(config)
119
+ if (!prefix) return null
120
+ return `${prefix}${fileBaseNoExt}`
121
+ }
122
+
123
+ function injectVueComponentName(content, name) {
124
+ if (/\bdefineOptions\s*\(/.test(content)) return content
125
+ const safe = String(name).replace(/[^A-Za-z0-9_]/g, '')
126
+ if (!safe) return content
127
+ const injectLine = `defineOptions({ name: '${safe}' })\n`
128
+ const m = content.match(/<script setup[^>]*>/)
129
+ if (!m || m.index === undefined) return content
130
+ const end = m.index + m[0].length
131
+ return `${content.slice(0, end)}\n${injectLine}${content.slice(end)}`
132
+ }
133
+
134
+ function hasKiloModuleConfig(cwd) {
135
+ return CONFIG_MODULES.some((name) => existsSync(join(cwd, name)))
136
+ }
137
+
138
+ function loadProjectConfigFromDisk(cwd) {
139
+ const jiti = createJiti(cliEntry, { interopDefault: true, cwd })
140
+
141
+ for (const name of CONFIG_MODULES) {
142
+ const p = join(cwd, name)
143
+ if (!existsSync(p)) continue
144
+ try {
145
+ const mod = jiti(p)
146
+ const raw = mod?.default ?? mod
147
+ if (!raw || typeof raw !== 'object') {
148
+ fail(`${name} must default-export a config object.`)
149
+ }
150
+ return normalizeConfig(raw)
151
+ } catch (e) {
152
+ const msg = e instanceof Error ? e.message : String(e)
153
+ fail(`Failed to load ${name}: ${msg}`)
154
+ }
155
+ }
156
+
157
+ const uiPath = join(cwd, UI_JSON)
158
+ if (existsSync(uiPath)) return normalizeConfig(readJson(uiPath))
159
+
160
+ const legacyPath = join(cwd, LEGACY_JSON)
161
+ if (existsSync(legacyPath)) return normalizeConfig(readJson(legacyPath))
162
+
163
+ return null
164
+ }
165
+
54
166
  function projectConfig() {
55
- const path = join(process.cwd(), configFile)
56
- if (!existsSync(path)) {
57
- fail(`Missing ${configFile}. Run "npx ${cliName} init" first.`)
167
+ const cwd = process.cwd()
168
+ const config = loadProjectConfigFromDisk(cwd)
169
+ if (!config) {
170
+ fail(
171
+ `Missing kilo.config.ts (or kilo.config.mjs, ${UI_JSON}, ${LEGACY_JSON}). Run "npx ${cliName} init" first.`,
172
+ )
58
173
  }
59
- return readJson(path)
174
+ return config
60
175
  }
61
176
 
62
177
  function aliasPath(config, key) {
63
178
  const value = config.aliases?.[key]
64
- if (!value) fail(`Missing aliases.${key} in ${configFile}`)
179
+ if (!value) fail(`Missing aliases.${key} in kilo.config / ${UI_JSON} / ${LEGACY_JSON}`)
65
180
  return value.replace(/^@\//, config.srcDir ? `${config.srcDir}/` : 'src/')
66
181
  }
67
182
 
@@ -69,28 +184,141 @@ function resolveTarget(config, alias, fileName) {
69
184
  return join(process.cwd(), aliasPath(config, alias), fileName)
70
185
  }
71
186
 
187
+ /** Path segments under the components alias (e.g. ["ui"] → …/components/ui/…). Empty string = no extra folder. */
188
+ function componentDirSegments(config) {
189
+ const dir = config.ui?.componentsDir
190
+ if (dir === '') return []
191
+ if (dir === undefined) return ['ui']
192
+ return String(dir).replace(/\\/g, '/').split('/').filter(Boolean)
193
+ }
194
+
72
195
  function componentFilePath(config, componentName, fileName) {
73
- return join(process.cwd(), aliasPath(config, 'components'), 'ui', componentName, fileName)
196
+ return join(
197
+ process.cwd(),
198
+ aliasPath(config, 'components'),
199
+ ...componentDirSegments(config),
200
+ componentName,
201
+ fileName,
202
+ )
74
203
  }
75
204
 
76
205
  function copyRegistryFile(sourceRelative, targetPath, config, force) {
77
206
  const sourcePath = join(registryRoot, sourceRelative)
78
207
  if (!existsSync(sourcePath)) fail(`Registry file not found: ${sourceRelative}`)
79
- const content = readFileSync(sourcePath, 'utf8')
208
+ let content = readFileSync(sourcePath, 'utf8')
80
209
  .replaceAll('__COMPONENTS_ALIAS__', config.aliases.components)
81
210
  .replaceAll('__COMPOSABLES_ALIAS__', config.aliases.composables)
82
211
  .replaceAll('__LIB_ALIAS__', config.aliases.lib)
83
212
  .replaceAll('__TYPES_ALIAS__', config.aliases.types)
213
+
214
+ if (targetPath.endsWith('.vue')) {
215
+ const base = basename(targetPath, '.vue')
216
+ const devName = vueResolvedComponentName(config, base)
217
+ if (devName) content = injectVueComponentName(content, devName)
218
+ }
219
+
84
220
  writeFile(targetPath, content, force)
85
221
  }
86
222
 
223
+ /**
224
+ * Vite resolves `@` from vite.config; TypeScript needs matching paths or `@/…` imports fail in the editor / vue-tsc.
225
+ * Vue templates usually keep env.d.ts at the project root next to tsconfig.app.json (not under src/).
226
+ */
227
+ function kiloConfigSerializable(config) {
228
+ const n = normalizeConfig(config)
229
+ return {
230
+ style: n.style ?? 'default',
231
+ srcDir: n.srcDir,
232
+ ui: n.ui,
233
+ tailwind: n.tailwind,
234
+ aliases: n.aliases,
235
+ }
236
+ }
237
+
238
+ function buildKiloConfigFileContent(config) {
239
+ const obj = kiloConfigSerializable(config)
240
+ const body = JSON.stringify(obj, null, 2)
241
+ const header = `// Kilo UI — app config (generated in your project root by ${pkgName}, not inside the library package)\n// ui.componentsDir / componentsPrefix = folder under aliases.components (default "ui")\n// If folder is not "ui", copied .vue files get defineOptions({ name: "<Prefix><FileName>" }) for <PrefixFileName /> in templates (override with ui.componentTagPrefix: false or a string).\n\n`
242
+ return `${header}import { defineConfig } from '${pkgName}/config'\n\nexport default defineConfig(${body})\n`
243
+ }
244
+
245
+ /** Create kilo.config.ts when missing, or overwrite when force (unless a non-.ts kilo module is the only config). */
246
+ function writeKiloConfigTs(cwd, config, force) {
247
+ const kiloPath = join(cwd, KILO_TS)
248
+ if (hasKiloModuleConfig(cwd) && !force) return
249
+ if (!force && existsSync(kiloPath)) return
250
+
251
+ const rel = relative(cwd, kiloPath)
252
+ const existed = existsSync(kiloPath)
253
+ ensureDir(dirname(kiloPath))
254
+ writeFileSync(kiloPath, buildKiloConfigFileContent(config), 'utf8')
255
+ log(`${force || existed ? 'write' : 'add'} ${rel}`)
256
+ }
257
+
258
+ function mergeTsconfigForAliases(cwd, srcDir = 'src') {
259
+ const srcNorm = String(srcDir || 'src').replace(/\\/g, '/').replace(/\/$/, '') || 'src'
260
+ const pathPattern = `./${srcNorm}/*`
261
+ const appPath = join(cwd, 'tsconfig.app.json')
262
+ const rootPath = join(cwd, 'tsconfig.json')
263
+
264
+ function tryMerge(filePath) {
265
+ if (!existsSync(filePath)) return false
266
+ let parsed
267
+ try {
268
+ parsed = readJson(filePath)
269
+ } catch {
270
+ log(`skip ${relative(cwd, filePath)} (invalid JSON — fix or add paths manually)`)
271
+ return false
272
+ }
273
+ const relName = relative(cwd, filePath)
274
+ if (relName === 'tsconfig.json' && parsed.references?.length && !parsed.compilerOptions) {
275
+ return false
276
+ }
277
+ parsed.compilerOptions = parsed.compilerOptions || {}
278
+ const co = parsed.compilerOptions
279
+ const paths = { ...(co.paths || {}) }
280
+ const key = '@/*'
281
+ if (paths[key]?.[0] === pathPattern) {
282
+ log(`skip ${relName} (paths "@/*" already set)`)
283
+ return true
284
+ }
285
+ if (paths[key]?.length) {
286
+ log(
287
+ `skip ${relName} (paths "@/*" already defined — ensure it points at your ${srcNorm}/ folder for kilo-ui imports)`,
288
+ )
289
+ return true
290
+ }
291
+ paths[key] = [pathPattern]
292
+ co.paths = paths
293
+ if (co.baseUrl === undefined) co.baseUrl = '.'
294
+
295
+ if (Array.isArray(parsed.include)) {
296
+ const hasEnv = parsed.include.some((entry) => String(entry).includes('env.d.ts'))
297
+ if (!hasEnv) parsed.include.unshift('env.d.ts')
298
+ }
299
+
300
+ writeJson(filePath, parsed)
301
+ log(`update ${relName} (TypeScript paths for @ + env.d.ts in include)`)
302
+ return true
303
+ }
304
+
305
+ if (tryMerge(appPath)) return
306
+ if (tryMerge(rootPath)) return
307
+
308
+ log('\nTip: Add TypeScript paths so editors resolve @ imports (same folder as vite alias):')
309
+ log(` "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["${pathPattern}"] } }`)
310
+ }
311
+
87
312
  function init(args) {
88
313
  const force = args.includes('--force')
89
- const configPath = join(process.cwd(), configFile)
90
- const defaultConfig = {
91
- $schema: 'https://kilo-ui.local/schema.json',
314
+ const cwd = process.cwd()
315
+ const uiPath = join(cwd, UI_JSON)
316
+ const legacyPath = join(cwd, LEGACY_JSON)
317
+
318
+ const defaultConfig = normalizeConfig({
92
319
  style: 'default',
93
320
  srcDir: 'src',
321
+ ui: { componentsDir: 'ui' },
94
322
  tailwind: {
95
323
  css: 'src/styles/teamwork-ui.css',
96
324
  },
@@ -100,23 +328,48 @@ function init(args) {
100
328
  lib: '@/lib',
101
329
  types: '@/types',
102
330
  },
103
- }
104
- const config = existsSync(configPath) && !force ? readJson(configPath) : defaultConfig
331
+ })
332
+
333
+ let config
105
334
 
106
- if (existsSync(configPath) && !force) {
107
- log(`skip ${configFile} (already exists)`)
335
+ if (!force) {
336
+ if (hasKiloModuleConfig(cwd)) {
337
+ config = loadProjectConfigFromDisk(cwd)
338
+ if (!config) fail('Could not read kilo config.')
339
+ log(`skip kilo.config.* (already exists)`)
340
+ } else if (existsSync(uiPath)) {
341
+ config = normalizeConfig(readJson(uiPath))
342
+ log(`using ${UI_JSON} (legacy). Prefer ${KILO_TS} — run init on a fresh branch or add the file from docs.`)
343
+ } else if (existsSync(legacyPath)) {
344
+ config = normalizeConfig(readJson(legacyPath))
345
+ log(`using ${LEGACY_JSON} (legacy fields). Adding ${KILO_TS} if missing.`)
346
+ } else {
347
+ config = defaultConfig
348
+ }
108
349
  } else {
109
- writeJson(configPath, config)
110
- log(`write ${configFile}`)
350
+ config = defaultConfig
111
351
  }
112
352
 
353
+ writeKiloConfigTs(cwd, config, force)
354
+
355
+ // Create the base folder for installed components so users can see it immediately after install/init.
356
+ // Actual component subfolders are created by `kilo-ui add`.
357
+ const baseComponents = join(cwd, aliasPath(config, 'components'), ...componentDirSegments(config))
358
+ if (baseComponents) ensureDir(baseComponents)
359
+
113
360
  copyRegistryFile('styles/teamwork-ui.css', join(process.cwd(), config.tailwind.css), config, force)
114
361
  copyRegistryFile('lib/utils.ts', resolveTarget(config, 'lib', 'utils.ts'), config, force)
362
+ copyRegistryFile('vue/env.d.ts', join(process.cwd(), 'env.d.ts'), config, force)
363
+
364
+ mergeTsconfigForAliases(process.cwd(), config.srcDir || 'src')
115
365
 
366
+ const sub = componentDirSegments(config).join('/') || '(components root)'
116
367
  log('\nDone. Add this once in your app entry or main stylesheet:')
117
368
  log(` import './styles/${config.tailwind.css.replace(/^.*\//, '')}'`)
369
+ log(`\nComponents install under: ${aliasPath(config, 'components').replace(/\\/g, '/')}/${sub}/<name>/`)
118
370
  log('\nThen add components:')
119
371
  log(` npx ${cliName} add data-table app-navbar activity-log`)
372
+ log(`\nEdit ${KILO_TS} to change where components install (aliases, ui.componentsDir).`)
120
373
  }
121
374
 
122
375
  function add(args) {
@@ -163,6 +416,8 @@ Usage:
163
416
  npx ${cliName} add <component...> [--force]
164
417
  npx ${cliName} list
165
418
 
419
+ Config: ${KILO_TS} (or ${KILO_MJS}, legacy ${UI_JSON} / ${LEGACY_JSON}). Use defineConfig from "${pkgName}/config". Set ui.componentsDir for the folder under your components alias (default "ui").
420
+
166
421
  Examples:
167
422
  npx ${cliName} init
168
423
  npx ${cliName} add data-table app-navbar
@@ -1,20 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import { existsSync } from 'node:fs'
3
- import { dirname, join, resolve } from 'node:path'
3
+ import { basename, dirname, join, resolve } from 'node:path'
4
4
  import { fileURLToPath } from 'node:url'
5
5
  import { spawnSync } from 'node:child_process'
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url))
8
8
  const packageRoot = resolve(__dirname, '..')
9
9
 
10
- const initCwd = process.env.INIT_CWD
10
+ const initCwd = resolveConsumerProjectRoot()
11
11
  if (!initCwd) process.exit(0)
12
12
 
13
13
  // Avoid running when installing this repo itself.
14
- if (resolve(initCwd) === packageRoot) process.exit(0)
14
+ if (resolve(initCwd) === resolve(packageRoot)) process.exit(0)
15
15
 
16
- // Only run once; if the user already initialized, do nothing.
17
- if (existsSync(join(initCwd, 'components.json'))) process.exit(0)
16
+ // Only skip auto-init when a kilo config module already exists.
17
+ // Do not treat components.json / ui.json as "done" — shadcn and other tools use those too,
18
+ // and we still need to add kilo.config.ts.
19
+ const kiloModuleNames = ['kilo.config.ts', 'kilo.config.mts', 'kilo.config.js', 'kilo.config.mjs']
20
+ if (kiloModuleNames.some((name) => existsSync(join(initCwd, name)))) process.exit(0)
18
21
 
19
22
  const cliEntry = join(packageRoot, 'bin', 'kilo-ui.mjs')
20
23
 
@@ -24,3 +27,21 @@ const result = spawnSync(process.execPath, [cliEntry, 'init'], {
24
27
  })
25
28
 
26
29
  process.exit(result.status ?? 1)
30
+
31
+ /**
32
+ * Prefer npm's INIT_CWD or npm_config_local_prefix. If missing, infer the app root only when
33
+ * this package lives under node_modules (never guess from a bare repo path).
34
+ */
35
+ function resolveConsumerProjectRoot() {
36
+ const fromEnv = process.env.INIT_CWD || process.env.npm_config_local_prefix
37
+ if (fromEnv) return resolve(fromEnv)
38
+
39
+ const norm = packageRoot.replace(/\\/g, '/')
40
+ if (!norm.includes('/node_modules/')) return null
41
+
42
+ const parent = dirname(packageRoot)
43
+ if (basename(parent).startsWith('@')) {
44
+ return resolve(parent, '..', '..')
45
+ }
46
+ return resolve(parent, '..')
47
+ }
@@ -0,0 +1,32 @@
1
+ export interface KiloUiUserConfig {
2
+ /** @deprecated informational only */
3
+ $schema?: string
4
+ style?: string
5
+ srcDir?: string
6
+ ui?: {
7
+ /**
8
+ * Folder prefix under `aliases.components` where `kilo-ui add` places each component
9
+ * (default `"ui"` → e.g. `src/components/ui/<name>/`). Use `""` for `…/components/<name>/`.
10
+ */
11
+ componentsDir?: string
12
+ /** Same as `componentsDir` if you prefer the name “prefix”. */
13
+ componentsPrefix?: string
14
+ /**
15
+ * Pascal prefix for Vue `defineOptions({ name })` on copied `.vue` files so you can use
16
+ * `<KiCardBox />` in templates when folder prefix is `ki` (auto: from first folder segment unless it is `ui`).
17
+ * Set a string to force (e.g. `"Ki"`). Set `false` to disable injection.
18
+ */
19
+ componentTagPrefix?: string | false
20
+ }
21
+ tailwind?: {
22
+ css: string
23
+ }
24
+ aliases: {
25
+ components: string
26
+ composables: string
27
+ lib: string
28
+ types: string
29
+ }
30
+ }
31
+
32
+ export function defineConfig(config: KiloUiUserConfig): KiloUiUserConfig
@@ -0,0 +1,4 @@
1
+ /** @param {import('./define-config.d.ts').KiloUiUserConfig} config */
2
+ export function defineConfig(config) {
3
+ return config
4
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Example config shipped with the npm package at:
3
+ * node_modules/@lyda/kilo-ui/config/kilo.config.example.ts
4
+ *
5
+ * Your Vue app does NOT edit this file. On `npm install`, the CLI creates
6
+ * **`kilo.config.ts` in your project root** (next to package.json).
7
+ *
8
+ * Change **`ui.componentsDir`** to set the folder prefix under your components path
9
+ * (e.g. `"ui"` → src/components/ui/data-table/…). Use `componentsPrefix` as an alias.
10
+ *
11
+ * With a non-`ui` folder (e.g. `"ki"`), `kilo-ui add` injects `defineOptions({ name: "KiCardBox" })`
12
+ * so you can use `<KiCardBox />` in templates. Override with `ui.componentTagPrefix` (`string` or `false`).
13
+ */
14
+ import { defineConfig } from '@lyda/kilo-ui/config'
15
+
16
+ export default defineConfig({
17
+ style: 'default',
18
+ srcDir: 'src',
19
+ ui: {
20
+ /** Folder prefix under `aliases.components` for copied registry components */
21
+ componentsDir: 'ui',
22
+ /** Set `false` to skip defineOptions name injection; set a string to force tag prefix */
23
+ // componentTagPrefix: false,
24
+ },
25
+ tailwind: {
26
+ css: 'src/styles/teamwork-ui.css',
27
+ },
28
+ aliases: {
29
+ components: '@/components',
30
+ composables: '@/composables',
31
+ lib: '@/lib',
32
+ types: '@/types',
33
+ },
34
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyda/kilo-ui",
3
- "version": "0.1.1",
3
+ "version": "0.1.5",
4
4
  "description": "shadcn-style Vue component registry for team CRUD apps",
5
5
  "type": "module",
6
6
  "repository": {
@@ -17,8 +17,15 @@
17
17
  "bin": {
18
18
  "kilo-ui": "bin/kilo-ui.mjs"
19
19
  },
20
+ "exports": {
21
+ "./config": {
22
+ "types": "./config/define-config.d.ts",
23
+ "default": "./config/define-config.mjs"
24
+ }
25
+ },
20
26
  "files": [
21
27
  "bin",
28
+ "config",
22
29
  "registry",
23
30
  "README.md"
24
31
  ],
@@ -49,5 +56,8 @@
49
56
  "crud",
50
57
  "ui"
51
58
  ],
52
- "license": "MIT"
59
+ "license": "MIT",
60
+ "dependencies": {
61
+ "jiti": "^2.7.0"
62
+ }
53
63
  }
@@ -0,0 +1,7 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ declare module '*.vue' {
4
+ import type { DefineComponent } from 'vue'
5
+ const component: DefineComponent<object, object, any>
6
+ export default component
7
+ }