Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 43 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Publish to npm
on:
release:
types: [published]
workflow_dispatch:

jobs:
publish:
name: Build and publish
runs-on: ubuntu-latest

permissions:
contents: read
id-token: write

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
- name: Verify ref is a release tag matching package.json version
env:
GITHUB_REF_NAME: ${{ github.ref_name }}
GITHUB_REF_TYPE: ${{ github.ref_type }}
run: |
if [ "$GITHUB_REF_TYPE" != "tag" ]; then
echo "Refusing to publish from $GITHUB_REF_TYPE '$GITHUB_REF_NAME'; publish only from a release tag." >&2
exit 1
fi
version=$(bun -e "console.log(require('./packages/svelte-querybuilder/package.json').version)")
if [ "$GITHUB_REF_NAME" != "v$version" ] && [ "$GITHUB_REF_NAME" != "$version" ]; then
echo "Tag '$GITHUB_REF_NAME' does not match package.json version '$version'." >&2
exit 1
fi
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020
with:
node-version: 24
registry-url: 'https://registry.npmjs.org'
- run: bun install --frozen-lockfile
- run: bun run build
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- run: npm publish
working-directory: packages/svelte-querybuilder
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Query state is now owned entirely by Svelte runes. `QueryManager` is gone from this package: core's pure functions (`add`/`remove`/`update`/`move`, `createQueryActions`, `prepareOptionList`, `deriveRuleContext`, `shouldCoalesce`) supply the logic, and the reactive graph lives in `$state`/`$derived`. `createQueryBuilderState` contains no `$effect` at all, and no longer relies on deep-compare, live closures, a config-version counter, subscription mirroring, or try/catch around immer's freeze.

Control elements are now composed the Svelte way. Each of the 24 control names is a top-level snippet prop, so `{#snippet valueEditor(props)}` works as a direct child of `<QueryBuilder>`, and the internal component-ABI trick that used to make snippets and components interchangeable is gone.
Control elements are now composed the Svelte way. Each of the 25 control names is a top-level snippet prop, so `{#snippet valueEditor(props)}` works as a direct child of `<QueryBuilder>`, and the internal component-ABI trick that used to make snippets and components interchangeable is gone.

### Removed

Expand All @@ -28,6 +28,8 @@ Control elements are now composed the Svelte way. Each of the 24 control names i
- Top-level snippet props for every control: `valueEditor`, `removeRuleAction`, `ruleGroup`, `actionElement`, `valueSelector`, and so on. A snippet declared inside a component's tags only becomes a prop when the name is top-level, which is what makes the idiomatic form reachable.
- `controls`, the bulk object form, for configuration assembled programmatically. It accepts components, `null`, and snippets wrapped as `{ snippet }`.
- A SvelteKit development playground at `packages/svelte-querybuilder/src/routes`, run with `bun run dev`. It imports library source (`$lib`) and core's SCSS rather than anything in `dist`, so component _and_ stylesheet edits hot-reload without a build. The package is now a SvelteKit project for this reason alone — `svelte-package` still reads `src/lib` and nothing else, and nothing under `src/routes` is published.
- **Ungroup**, ported from core 8.24.0. Set `showUngroupButtons` to render an "Ungroup" button (`⊟`) in the header of every group except the root, which replaces that group with its own rules in the parent. Adds the `ungroupAction` control — defaulting to `ActionElement`, overridable as a top-level snippet prop or a `controls` entry, and a target of the `actionElement` bulk override like every other `controlKind: 'action'` key — the `onUngroup` callback prop (return `false` to cancel or a replacement query to substitute one, matching `onMoveRule`/`onGroupRule`), and `ungroupRuleGroup` on `RuleGroupParts`.
- **Conformance fixtures now track upstream `v8.24.3`** (from `v8.23.0`). The `allControls` scenario gains `showUngroupButtons`, which is what proves the new button's placement, class, and label byte-for-byte against React's output.

### Changed

Expand All @@ -49,7 +51,14 @@ Control elements are now composed the Svelte way. Each of the 24 control names i
- `Rule`, `RuleGroup`, and `ValueEditor` are generic over the same `F`/`O`. `ValueEditor` previously hardcoded `ValueEditorProps<FullField, string>`, so a replacement value editor was better typed than the built-in one.
- `RuleComponents` takes `mode`, `rule: { props, parts }`, and (in `subQuery` mode) `subQuery: { props, parts }`, replacing four flat props. The two `(props, parts)` pairs — the rule's, and the subquery's own query-builder state — are now visibly paired, and whether a rule renders a `matchModeEditor` is decided by the explicit `mode` discriminator rather than by the presence of the subquery state.
- `QueryBuilder` publishes context as `setQueryBuilderContext(() => state.context)` rather than an `Object.defineProperty` reflection loop, so the key set is no longer snapshotted at initialization. `getQueryBuilderContext` returns a getter.
- Minimum `@react-querybuilder/core` is now 8.23.0, for the query-tool `freeze` opt-out (deep-freezing a Svelte `$state` proxy throws), `shouldCoalesce`, `controlKeys`/`controlKind`, and `DefaultFieldProp`/`DefaultOperatorProp`.
- **Breaking:** every `context` is typed `unknown` instead of `any` — the free-form `context` prop on subcomponents and `QueryBuilder`, the `context` argument to `onAddRule`/`onAddGroup`/`onMoveRule`/`onMoveGroup`/`onGroupRule`/`onGroupGroup`/`onRemove`, and `ActionProps.handleOnClick`'s second argument. `onLog` takes `unknown`. Narrow before use.
- **Breaking:** `Schema.getSubQueryBuilderProps` returns the new, exported `SubQueryBuilderProps` type and accepts any field name (`string`), and the internal implementation no longer returns `any`. Removes every `as never` from `RuleSubQuery`.
- `Control` (the internal renderer) is generic over the control's props, so each built-in call site's props are type-checked against the control's prop type instead of passing through `any`. This caught `MatchModeEditor`'s threshold editor passing `valueSource` as `string` rather than `ValueSource`.
- Remaining casts and `any`s in `src/lib` are either removed or annotated with the reason they stay, which is almost always a match for an `any` in core (`RuleType.value`, `QueryActions`).
- A unit test caps `$effect` use in `src/lib` to an explicit allow-list (today, the single value-editor reset). Another checks this package's control keys against core's `controlKeys`/`controlKind` at runtime, alongside the existing compile-time guard.
- When a conformance class-name comparison fails only on whitespace in an element's own text, the failure message now points to the `<!-- -->` joiners.
- New [Reactivity notes](./docs/reactivity.md) doc, and a "Stability and versioning" README section covering the core version policy and what blocks 1.0.
- Minimum `@react-querybuilder/core` is now 8.24.3, for ungroup (8.24.0), the query-tool `freeze` opt-out (deep-freezing a Svelte `$state` proxy throws), `shouldCoalesce`, `controlKeys`/`controlKind`, and `DefaultFieldProp`/`DefaultOperatorProp`.

### Fixed

Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ The DOM is class-compatible with React Query Builder, so existing RQB stylesheet
- [Differences from React Query Builder](./docs/differences-from-react-querybuilder.md) — start here if you know RQB
- [Customization](./docs/customization.md) — snippets, `controls`, translations, context
- [Styling](./docs/styling.md)
- [Reactivity notes](./docs/reactivity.md) — stable `query` references, context getters, writing custom controls
- Concepts, field/operator configuration, query formats, and parsers: the [React Query Builder documentation](https://react-querybuilder.js.org/docs/intro) applies directly, since the logic layer is shared.

## Examples
Expand All @@ -85,6 +86,18 @@ Not in v1, and not planned for the near term:
- A Redux store or a `qbId` registry — hold the query yourself and use `bind:query`
- Deprecated props carried over from React Query Builder

## Stability and versioning

Pre-1.0: minor releases (`0.x`) may break the component API. Breaking changes are listed in [`CHANGELOG.md`](./CHANGELOG.md).

**Core version policy.** `@react-querybuilder/core` is a caret dependency on a minor (currently `^8.24.3`). The conformance fixtures are pinned to the matching React Query Builder tag, and the two move together: raising the core minimum means bumping the fixture tag and passing conformance against it. Core's public API, including the headless derivations this package uses, is semver-covered upstream.

**What blocks 1.0:**

- A release with no breaking change to the component API: props, control names and their prop types, `Schema`, the `create*Parts` helpers, and the context functions.
- DOM conformance green against the then-current React Query Builder release, with the text channel enabled.
- The non-goals above staying non-goals. 1.0 doesn't depend on any of them, and adding one later won't be a breaking change.

## License

MIT
Loading
Loading