Skip to content
Merged
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
20 changes: 14 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @wedevs/plugin-ui

> **Note (DOKAN_NEXT_MAJOR):** The `dependency_key` attribute has been removed
> from the settings schema. Use the field's `id` directly. `show_if` and
> `dependencies` rule keys are now flat field ids — dot-paths are no longer
> supported. See the [dependency_key cleanup plan][cleanup-plan] for migration
> context.
>
> [cleanup-plan]: https://github.com/getdokan/dokan/blob/refactor/simplify-settings-to-flat-array/docs/superpowers/plans/2026-05-18-dependency-key-cleanup.md

Scoped, themeable React component library for WordPress plugins. Built on ShadCN patterns, Tailwind CSS v4, and Base-UI primitives.

## Architecture
Expand Down Expand Up @@ -55,15 +63,15 @@ import { Settings } from '@wedevs/plugin-ui';

<Settings
schema={settingsSchema} // SettingsElement[] (flat or hierarchical)
values={values} // Record<string, any> keyed by dependency_key
values={values} // Record<string, any> keyed by field id
onChange={(scopeId, key, value) => {
setValues(prev => ({ ...prev, [key]: value }));
}}
onSave={async (scopeId, treeValues, flatValues) => {
// treeValues: nested object built from dot-separated keys
// e.g. { dokan: { general: { store_name: "..." } } }
// flatValues: original flat dot-keyed values
// e.g. { "dokan.general.store_name": "..." }
// treeValues: object keyed by field id
// e.g. { store_name: "...", enable_tax: true }
// flatValues: same shape — flat id-keyed values
// e.g. { store_name: "...", enable_tax: true }
await api.post(`/settings/${scopeId}`, treeValues);
}}
renderSaveButton={({ dirty, hasErrors, onSave }) => (
Expand All @@ -76,7 +84,7 @@ import { Settings } from '@wedevs/plugin-ui';

### Key Concepts

- **`dependency_key`**: Unique key on each field element, used as the key in `values` and `flatValues`
- **`id`**: Unique key on each field element, used as the key in `values` and `flatValues`
- **Dependencies**: Elements can conditionally show/hide based on other field values via `dependencies` array
- **Validation**: Per-field `validations` array with rules and error messages
- **Dirty tracking**: Per-scope (subpage/page) dirty state; resets only on successful save
Expand Down
11 changes: 8 additions & 3 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# @wedevs/plugin-ui — Developer Guide

> **Note (DOKAN_NEXT_MAJOR):** The `dependency_key` attribute has been removed
> from the settings schema. Use the field's `id` directly. `show_if` and
> `dependencies` rule keys are now flat field ids — dot-paths are no longer
> supported. See the [dependency_key cleanup plan][cleanup-plan] for migration
> context.
>
> [cleanup-plan]: https://github.com/getdokan/dokan/blob/refactor/simplify-settings-to-flat-array/docs/superpowers/plans/2026-05-18-dependency-key-cleanup.md

A ShadCN-style React component library built for WordPress plugins. Provides 50+ themed, accessible UI components powered by Tailwind CSS v4, `@base-ui/react` headless primitives, and first-class WordPress integration.

---
Expand Down Expand Up @@ -1088,23 +1096,20 @@ const schema: SettingsElement[] = [
type: 'field',
variant: 'text',
label: __('Store Name', 'my-plugin'),
dependency_key: 'store_name',
default: '',
},
{
id: 'enable_tax',
type: 'field',
variant: 'switch',
label: __('Enable Tax', 'my-plugin'),
dependency_key: 'enable_tax',
default: false,
},
{
id: 'tax_rate',
type: 'field',
variant: 'number',
label: __('Tax Rate (%)', 'my-plugin'),
dependency_key: 'tax_rate',
dependencies: [{ key: 'enable_tax', value: true, comparison: '=' }],
},
],
Expand Down
12 changes: 9 additions & 3 deletions src/DeveloperGuide.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { Meta } from "@storybook/addon-docs/blocks";

# @wedevs/plugin-ui — Developer Guide

> **Note (DOKAN_NEXT_MAJOR):** The `dependency_key` attribute has been removed
> from the settings schema. Use the field's `id` directly. `show_if` and
> `dependencies` rule keys are now flat field ids — dot-paths are no longer
> supported. See the [dependency_key cleanup plan](https://github.com/getdokan/dokan/blob/refactor/simplify-settings-to-flat-array/docs/superpowers/plans/2026-05-18-dependency-key-cleanup.md)
> for migration context.

A ShadCN-style React component library built for WordPress plugins. Provides 50+ themed, accessible UI components powered by Tailwind CSS v4, `@base-ui/react` headless primitives, and first-class WordPress integration.

---
Expand Down Expand Up @@ -892,9 +898,9 @@ const schema: SettingsElement[] = [
children: [{
id: 'basic_section', type: 'section', label: __('Basic Settings', 'my-plugin'),
children: [
{ id: 'store_name', type: 'field', variant: 'text', label: __('Store Name', 'my-plugin'), dependency_key: 'store_name', default: '' },
{ id: 'enable_tax', type: 'field', variant: 'switch', label: __('Enable Tax', 'my-plugin'), dependency_key: 'enable_tax', default: false },
{ id: 'tax_rate', type: 'field', variant: 'number', label: __('Tax Rate (%)', 'my-plugin'), dependency_key: 'tax_rate',
{ id: 'store_name', type: 'field', variant: 'text', label: __('Store Name', 'my-plugin'), default: '' },
{ id: 'enable_tax', type: 'field', variant: 'switch', label: __('Enable Tax', 'my-plugin'), default: false },
{ id: 'tax_rate', type: 'field', variant: 'number', label: __('Tax Rate (%)', 'my-plugin'),
dependencies: [{ key: 'enable_tax', value: true, comparison: '=' }] },
],
}],
Expand Down
48 changes: 24 additions & 24 deletions src/components/settings/Settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { Meta } from "@storybook/addon-docs/blocks";

# Settings Component

> **Note (DOKAN_NEXT_MAJOR):** The `dependency_key` attribute has been removed
> from the settings schema. Use the field's `id` directly. `show_if` and
> `dependencies` rule keys are now flat field ids — dot-paths are no longer
> supported. See the [dependency_key cleanup plan](https://github.com/getdokan/dokan/blob/refactor/simplify-settings-to-flat-array/docs/superpowers/plans/2026-05-18-dependency-key-cleanup.md)
> for migration context.

A reusable, schema-driven settings page that renders a full UI from a JSON structure.
Designed for WordPress plugin settings with built-in extensibility.

Expand Down Expand Up @@ -51,11 +57,10 @@ const schema: SettingsElement[] = [
label: "Main",
children: [
{
id: "site_name_field",
id: "site_name",
type: "field",
variant: "text",
label: "Site Name",
dependency_key: "site_name",
default: "",
},
],
Expand All @@ -78,8 +83,8 @@ function MySettingsPage() {
setValues((prev) => ({ ...prev, [key]: value }));
}}
onSave={(scopeId, treeValues, flatValues) => {
// treeValues: nested object from dot-separated keys
// flatValues: original flat dot-keyed values
// treeValues: object keyed by field id
// flatValues: same shape — flat id-keyed values
console.log("Saving", scopeId, treeValues, flatValues);
}}
renderSaveButton={({ dirty, hasErrors, onSave }) => (
Expand Down Expand Up @@ -277,15 +282,13 @@ Groups multiple fields in a horizontal row (e.g. min/max pair).
"id": "min_price",
"type": "field",
"variant": "number",
"label": "Min",
"dependency_key": "min_price"
"label": "Min"
},
{
"id": "max_price",
"type": "field",
"variant": "number",
"label": "Max",
"dependency_key": "max_price"
"label": "Max"
}
]
}
Expand All @@ -297,13 +300,12 @@ An individual form input. The `variant` determines which UI control renders.

```json
{
"id": "store_name_field",
"id": "store_name",
"type": "field",
"variant": "text",
"label": "Store Name",
"description": "The display name of your store.",
"tooltip": "Visible to customers.",
"dependency_key": "store_name",
"default": "My Store",
"placeholder": "Enter store name"
}
Expand Down Expand Up @@ -400,8 +402,8 @@ Used by `select`, `radio_capsule`, `customize_radio`, and `multicheck`:

```json
{
"id": "enable_feature",
"variant": "switch",
"dependency_key": "enable_feature",
"enable_state": { "value": "on", "title": "Enabled" },
"disable_state": { "value": "off", "title": "Disabled" }
}
Expand Down Expand Up @@ -430,11 +432,10 @@ const flatData = [
{ id: "basic_tab", type: "tab", label: "Basic", subpage_id: "store" },
{ id: "main_section", type: "section", label: "Main", tab_id: "basic_tab" },
{
id: "name_field",
id: "store_name",
type: "field",
variant: "text",
label: "Store Name",
dependency_key: "store_name",
section_id: "main_section",
},
];
Expand Down Expand Up @@ -510,7 +511,7 @@ Fired whenever a field value changes.
<tr>
<td><code>key</code></td>
<td><code>string</code></td>
<td>The field's <code>dependency_key</code></td>
<td>The field's <code>id</code></td>
</tr>
<tr>
<td><code>value</code></td>
Expand Down Expand Up @@ -550,12 +551,12 @@ Fired when the save button is clicked. Only receives values **scoped to the acti
<tr>
<td><code>treeValues</code></td>
<td><code>{'Record<string, any>'}</code></td>
<td>Nested object built from dot-separated keys (e.g. <code>{'{"dokan":{"general":{"store_name":"..."}}}'}</code>)</td>
<td>Object keyed by field id (e.g. <code>{'{"store_name":"...","enable_tax":true}'}</code>)</td>
</tr>
<tr>
<td><code>flatValues</code></td>
<td><code>{'Record<string, any>'}</code></td>
<td>Original flat dot-keyed values (e.g. <code>{'{"dokan.general.store_name":"..."}'}</code>)</td>
<td>Same shape — flat id-keyed values (e.g. <code>{'{"store_name":"...","enable_tax":true}'}</code>)</td>
</tr>
</tbody>
</table>
Expand All @@ -574,7 +575,7 @@ Fired when the save button is clicked. Only receives values **scoped to the acti
### Server-Side Validation Errors

If your API returns field-level validation errors, **throw an object** with an `errors` property
from `onSave`. The keys must match field `dependency_key` values:
from `onSave`. The keys must match field `id` values:

```tsx
<Settings
Expand All @@ -587,9 +588,9 @@ from `onSave`. The keys must match field `dependency_key` values:

if (!res.ok) {
const data = await res.json();
// Throw with { errors: { [dependency_key]: "message" } }
// Throw with { errors: { [fieldId]: "message" } }
throw { errors: data.errors };
// e.g. { errors: { "dokan.general.store_name": "Store name already taken" } }
// e.g. { errors: { "store_name": "Store name already taken" } }
}
}}
/>
Expand Down Expand Up @@ -714,11 +715,10 @@ Fields can be conditionally shown/hidden based on other field values using the

```json
{
"id": "tax_rate_field",
"id": "tax_rate",
"type": "field",
"variant": "number",
"label": "Tax Rate (%)",
"dependency_key": "tax_rate",
"dependencies": [
{
"key": "enable_tax",
Expand All @@ -745,7 +745,7 @@ This field only appears when `enable_tax` is `true`.
<tr>
<td><code>key</code></td>
<td><code>string</code></td>
<td><code>dependency_key</code> of the field to watch</td>
<td><code>id</code> of the field to watch</td>
</tr>
<tr>
<td><code>value</code></td>
Expand Down Expand Up @@ -803,7 +803,7 @@ const schema = formatSettingsData(flatApiResponse);

### `extractValues(schema)`

Walks a hierarchical schema and extracts all `dependency_key` to `value` pairs into a flat object.
Walks a hierarchical schema and extracts all `id` to `value` pairs into a flat object.
Useful for initializing the `values` prop.

```tsx
Expand Down Expand Up @@ -839,7 +839,7 @@ const initialValues = extractValues(schema);
<td><code>values</code></td>
<td><code>{'Record<string, any>'}</code></td>
<td><code>{'{}'}</code></td>
<td>Current field values keyed by <code>dependency_key</code></td>
<td>Current field values keyed by <code>id</code></td>
</tr>
<tr>
<td><code>onChange</code></td>
Expand Down
Loading
Loading