Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
0b6218f
Update CLI
alexcibotari Feb 16, 2026
a8663d9
Update CLI
alexcibotari Feb 16, 2026
b2e8947
Update CLI
alexcibotari Feb 16, 2026
61da35d
Update CLI
alexcibotari Feb 16, 2026
a39382d
Update CLI
alexcibotari Feb 16, 2026
879e889
Update CLI
alexcibotari Feb 16, 2026
d0d939d
Update CLI
alexcibotari Feb 16, 2026
6e007e0
Update CLI
alexcibotari Feb 17, 2026
fdd16a7
Update CLI
alexcibotari Feb 17, 2026
ea4e214
Update CLI
alexcibotari Feb 17, 2026
7b6255c
Update CLI
alexcibotari Feb 17, 2026
1f6f503
Update CLI
alexcibotari Feb 17, 2026
ce47704
Update CLI
alexcibotari Feb 17, 2026
f85dbe2
Add Translation Draft version fetch
alexcibotari Feb 18, 2026
d8e91ce
Add fetch retry
alexcibotari Feb 20, 2026
c1a3063
update Type command
alexcibotari Feb 20, 2026
42272ed
Add Translations Pull
alexcibotari Feb 21, 2026
87efde3
Merge branch 'dev' of https://github.com/Lessify/localess-js into dev
alexcibotari Feb 21, 2026
3553070
Update Readme
alexcibotari Feb 21, 2026
53d8600
Update Push Type
alexcibotari Feb 22, 2026
2bed97b
Add Dry Run for Translations push
alexcibotari Feb 22, 2026
01522e0
Add Dry Run for Translations push
alexcibotari Feb 22, 2026
44531d7
update Type command
alexcibotari Feb 24, 2026
ef03ff2
Update References
alexcibotari Mar 7, 2026
9fae2c0
Update Build
alexcibotari Mar 7, 2026
9b52812
Update Build
alexcibotari Mar 7, 2026
7a4cd9b
Update Build
alexcibotari Mar 7, 2026
b82e55c
Update Build
alexcibotari Mar 7, 2026
6aaefd6
Update Build
alexcibotari Mar 7, 2026
1fffe76
Update Build
alexcibotari Mar 7, 2026
65cef47
Update Build
alexcibotari Mar 7, 2026
03ce0af
Update Build
alexcibotari Mar 7, 2026
8091d5e
Update Build
alexcibotari Mar 7, 2026
0b423a2
Update Documentation
alexcibotari Mar 7, 2026
cf7f2d9
update Type command
alexcibotari Mar 8, 2026
b7b8be3
update Type command
alexcibotari Mar 8, 2026
d4e7a86
Update Version
alexcibotari Mar 13, 2026
d42771a
Unification NPM Publish
alexcibotari Mar 13, 2026
7acef41
Unification NPM Publish
alexcibotari Mar 13, 2026
9165eff
Update Documentation
alexcibotari Mar 13, 2026
6a01066
Merge branch 'dev' of https://github.com/Lessify/localess-js into dev
alexcibotari Mar 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 39 additions & 20 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,24 @@ npm run build --workspace=@localess/react
npm run build --workspace=@localess/cli
```

All packages use `tsup` for building with the command:
All packages use `tsup` for building:
- `@localess/client` and `@localess/react`: `tsup src/index.ts --format cjs,esm --dts` → `dist/index.js`, `dist/index.mjs`, `dist/index.d.ts`
- `@localess/cli`: `tsup src/index.ts --format cjs,esm --dts --shims` → ESM only (`dist/index.mjs`), `--shims` adds Node.js polyfills for the CLI executable

## Test Commands

Tests only exist in `@localess/cli`. Run from the workspace root:

```bash
tsup src/index.ts --format cjs,esm --dts
```
# Run all CLI tests
npm test --workspace=@localess/cli

This generates:
- `dist/index.js` (CommonJS)
- `dist/index.mjs` (ESM)
- `dist/index.d.ts` (TypeScript declarations)
# Run a single test file
npx vitest run packages/cli/src/commands/login/login.test.ts

# Run tests in watch mode
npx vitest --workspace=@localess/cli
```

### Requirements

Expand Down Expand Up @@ -140,8 +149,8 @@ The component:
```tsx
const MyComponent = ({ data, links }) => {
return (
<div {...llEditable(data)}>
<h1 {...llEditableField('title')}>{data.title}</h1>
<div {...localessEditable(data)}>
<h1 {...localessEditableField('title')}>{data.title}</h1>
{data.children?.map(child => (
<LocalessComponent key={child._id} data={child} links={links} />
))}
Expand All @@ -151,9 +160,10 @@ const MyComponent = ({ data, links }) => {
```

**Visual Editor Integration**:
- `llEditable(content)` - Adds `data-ll-id` and `data-ll-schema` attributes to root element
- `llEditableField(fieldName)` - Adds `data-ll-field` attribute to specific fields
- `localessEditable(content)` - Adds `data-ll-id` and `data-ll-schema` attributes to root element
- `localessEditableField<T>(fieldName)` - Adds `data-ll-field` attribute to specific fields; generic type `T` restricts `fieldName` to valid content keys
- Only applied when `enableSync: true`
- `llEditable` / `llEditableField` are deprecated aliases — prefer `localessEditable` / `localessEditableField`
- Listen to editor events: `window.localess.on(['input', 'change'], callback)`

**Rich Text Rendering**:
Expand All @@ -180,9 +190,16 @@ resolveAsset(asset) // Returns: {origin}/api/v1/spaces/{spaceId}/assets/{uri}

### CLI Package (@localess/cli)

**Status**: Early development - only `login` command implemented.
**Status**: Early development (v0.0.6). Built with Commander.js. Entry point: `src/index.ts` with shebang `#!/usr/bin/env node`.

Built with Commander.js. Entry point: `src/index.ts` with shebang `#!/usr/bin/env node`.
**Implemented commands**:
- `login --origin <url> --space <id> --token <token>` — persists credentials to `.localess/credentials.json`
- `logout` — clears stored credentials
- `translations push <locale> --path <file> [--format flat|nested] [--type add-missing|replace]`
- `translations pull <locale> --path <file> [--format flat|nested]`
- `types generate [--path <output_file>]` — generates TypeScript types from OpenAPI schema (default output: `.localess/localess.d.ts`)

**CLI-specific client** (`src/client.ts`) extends the base client with retry logic (`fetchWithRetry`, 3 retries/500ms delay on 5xx), `getSpace()`, `updateTranslations()`, and `getOpenApi()`. Uses `zod` for input validation and `openapi-typescript` for type generation.

## Content Data Model

Expand Down Expand Up @@ -220,10 +237,10 @@ components: {

### Editable Attributes Pattern

When `enableSync: true`, always spread editable attributes on the root element and field elements:
When `enableSync: true`, always spread editable attributes on the root element and field elements. Use the preferred (non-deprecated) API:
```tsx
<article {...llEditable(data)}>
<h1 {...llEditableField('title')}>{data.title}</h1>
<article {...localessEditable(data)}>
<h1 {...localessEditableField('title')}>{data.title}</h1>
</article>
```

Expand Down Expand Up @@ -251,8 +268,9 @@ All packages use dual exports (CJS + ESM):
### Version Management

Packages follow semantic versioning:
- `@localess/client` and `@localess/react`: v0.9.2
- `@localess/cli`: v0.0.1 (early stage)
- `@localess/client`: v0.9.3
- `@localess/react`: v0.9.5
- `@localess/cli`: v0.0.6 (early stage)

## Common Patterns

Expand Down Expand Up @@ -288,16 +306,17 @@ useEffect(() => {
}
}
window.localess.on(['input', 'change'], handler)
return () => window.localess.off(['input', 'change'], handler)
}
}, [])
```

Note: `window.localess` only provides `.on()` and `.onChange()` — there is no `.off()` method.

### Nested Components Pattern

Content often has nested structures. Use recursive `LocalessComponent`:
```tsx
<div {...llEditable(data)}>
<div {...localessEditable(data)}>
{data.sections?.map(section => (
<LocalessComponent key={section._id} data={section} links={links} />
))}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ jobs:

strategy:
matrix:
node-version: [20.x, 22.x]
node-version: [20.x, 22.x, 24.x]

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
Expand Down
37 changes: 23 additions & 14 deletions .github/workflows/dev-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ jobs:
publish-snapshot:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Use Node.js 20.x
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: 20.x
registry-url: 'https://registry.npmjs.org/'
Expand All @@ -20,26 +20,35 @@ jobs:
- name: Install dependencies
run: npm ci

- name: Build all packages
run: npm run build

- name: Set snapshot version for all packages
- name: Set snapshot version from root package.json
run: |
DATE=$(date +"%Y%m%d%H%M%S")
for pkg in packages/*/package.json; do
jq ".version |= sub("-dev\\.[0-9]+"; "") | .version += "-dev.$DATE"" $pkg > tmp.$$.json && mv tmp.$$.json $pkg
VERSION="$(node -p "require('./package.json').version")-dev.${DATE}"
echo "Publishing snapshot version: $VERSION"
for pkgdir in packages/*/; do
pkg="${pkgdir}package.json"
jq --arg v "$VERSION" '
.version = $v |
if .dependencies then
.dependencies |= with_entries(if .key | startswith("@localess/") then .value = $v else . end)
else . end |
if .peerDependencies then
.peerDependencies |= with_entries(if .key | startswith("@localess/") then .value = $v else . end)
else . end
' "$pkg" > tmp.json && mv tmp.json "$pkg"
done
shell: bash

- name: Publish snapshot to npm with tag 'dev'
- name: Build all packages
run: npm run build

- name: Publish all packages to npm with tag 'dev'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
for pkg in packages/*/package.json; do
pkgdir=$(dirname $pkg)
if ! grep -q '"private"\s*:\s*true' $pkg; then
npm publish --tag dev --access public --workspace $(basename $pkgdir)
for pkgdir in packages/*/; do
if ! grep -q '"private"\s*:\s*true' "${pkgdir}package.json"; then
npm publish --tag dev --access public --workspace "$pkgdir"
fi
done
shell: bash

50 changes: 31 additions & 19 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,41 +1,53 @@
name: Publish to npm
name: Publish to npm (master branch)

on:
push:
tags:
- 'v*'
branches: [master]

jobs:
publish:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x, 22.x]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
- name: Use Node.js 20.x
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
node-version: 20.x
registry-url: 'https://registry.npmjs.org/'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Sync versions from root package.json
run: |
VERSION=$(node -p "require('./package.json').version")
echo "Publishing version: $VERSION"
for pkgdir in packages/*/; do
pkg="${pkgdir}package.json"
jq --arg v "$VERSION" '
.version = $v |
if .dependencies then
.dependencies |= with_entries(if .key | startswith("@localess/") then .value = $v else . end)
else . end |
if .peerDependencies then
.peerDependencies |= with_entries(if .key | startswith("@localess/") then .value = $v else . end)
else . end
' "$pkg" > tmp.json && mv tmp.json "$pkg"
done
shell: bash

- name: Build all packages
run: npm run build

- name: Publish packages to npm
- name: Publish all packages to npm
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm publish --workspaces --access public

- name: Verify published versions
run: |
npm info @localess/client | grep version
npm info @localess/react | grep version
npm info @localess/cli | grep version

for pkgdir in packages/*/; do
if ! grep -q '"private"\s*:\s*true' "${pkgdir}package.json"; then
npm publish --access public --workspace "$pkgdir"
fi
done
shell: bash
Loading