Skip to content

feat(form): allow end users to remove or reorder array items#3727

Merged
Kiarokh merged 3 commits intomainfrom
form-allow-item-removal-&-reorder
Nov 21, 2025
Merged

feat(form): allow end users to remove or reorder array items#3727
Kiarokh merged 3 commits intomainfrom
form-allow-item-removal-&-reorder

Conversation

@Kiarokh
Copy link
Contributor

@Kiarokh Kiarokh commented Nov 19, 2025

fix: https://github.com/Lundalogik/crm-client/issues/498

Summary by CodeRabbit

Release Notes

  • New Features
    • Array forms now support configurable item reordering and removal controls. End-users can toggle whether list items can be reordered or removed, enabling flexible control over data management operations.
    • New interactive example component demonstrates array item controls with toggles to enable/disable reordering and removal permissions, including live form state display and updates.

Review:

  • Commits are atomic
  • Commits have the correct type for the changes made
  • Commits with breaking changes are marked as such

Browsers tested:

(Check any that applies, it's ok to leave boxes unchecked if testing something didn't seem relevant.)

Windows:

  • Chrome
  • Edge
  • Firefox

Linux:

  • Chrome
  • Firefox

macOS:

  • Chrome
  • Firefox
  • Safari

Mobile:

  • Chrome on Android
  • iOS

@Kiarokh Kiarokh requested a review from a team as a code owner November 19, 2025 10:39
@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Adds support for controlling array item reordering and removal in form components by introducing two new optional properties to LimeSchemaOptions (allowItemReorder and allowItemRemoval). Updates existing array field templates to conditionally render action buttons based on these flags. Includes a new example component demonstrating the feature with toggleable permissions and live form binding.

Changes

Cohort / File(s) Summary
Type system updates
src/components/form/form.types.ts
Adds two new optional properties to LimeSchemaOptions: allowItemReorder and allowItemRemoval, with documentation comments.
Example schema and component
src/components/form/examples/array-item-controls-schema.ts, src/components/form/examples/array-item-controls-form.tsx
Introduces new interfaces (MissionPlan, ArrayItemControlsFormData), baseSchema constant, and FormArrayItemControlsExample component demonstrating editable arrays with toggleable reorder/removal permissions.
Array field templates
src/components/form/templates/array-field.ts, src/components/form/templates/array-field-collapsible-item.ts, src/components/form/templates/array-field-simple-item.ts
Adds new props (allowItemReorder, allowItemRemoval) to item templates; conditionally renders action buttons for reordering and removal based on flags; includes event listener refactoring in SimpleItemTemplate.
Documentation
src/components/form/form.tsx
Adds limel-example-form-array-item-controls to component documentation.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant Form as FormArrayItemControlsExample
    participant Template as ItemTemplate
    participant Schema as Schema Config

    User->>Form: Toggle allowItemReorder/allowItemRemoval
    Form->>Form: Update state flags
    Form->>Form: Recreate schema with lime options
    Form->>Template: Render with updated props
    
    alt allowItemReorder = true
        Template->>Template: Render up/down buttons
    end
    
    alt allowItemRemoval = true
        Template->>Template: Render remove button
    end
    
    Template->>User: Display conditionally available actions
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Event handler refactoring in SimpleItemTemplate: Review the migration from componentDidMount-based event binding to setXButton callback approach with proper cleanup in componentWillUnmount.
  • Conditional rendering logic: Verify correct behavior of allowItemReorder and allowItemRemoval flags across CollapsibleItemTemplate and SimpleItemTemplate.
  • Schema integration: Ensure getItemControls() method in array-field.ts correctly extracts and defaults control flags from schema.lime configuration.

Possibly related PRs

Suggested reviewers

  • john-traas

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: adding functionality for end users to remove or reorder array items in forms.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6234e9 and 2c49cef.

⛔ Files ignored due to path filters (1)
  • etc/lime-elements.api.md is excluded by !etc/lime-elements.api.md
📒 Files selected for processing (7)
  • src/components/form/examples/array-item-controls-form.tsx (1 hunks)
  • src/components/form/examples/array-item-controls-schema.ts (1 hunks)
  • src/components/form/form.tsx (1 hunks)
  • src/components/form/form.types.ts (1 hunks)
  • src/components/form/templates/array-field-collapsible-item.ts (2 hunks)
  • src/components/form/templates/array-field-simple-item.ts (5 hunks)
  • src/components/form/templates/array-field.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

**/*.{ts,tsx}: Imports from other files in the same module (lime-elements) must use relative paths. Using absolute paths for imports will cause the production build to fail.

Files:

  • src/components/form/form.types.ts
  • src/components/form/templates/array-field.ts
  • src/components/form/examples/array-item-controls-schema.ts
  • src/components/form/templates/array-field-collapsible-item.ts
  • src/components/form/templates/array-field-simple-item.ts
  • src/components/form/form.tsx
  • src/components/form/examples/array-item-controls-form.tsx
src/components/**/examples/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

src/components/**/examples/**/*.{ts,tsx}: These files are an exception to the rule that all imports should use relative paths. When these example files import something that is publicly exported by lime-elements, the import should be made from @limetech/lime-elements. If they import something from another file inside the example folder, the import should use a relative path.

Files:

  • src/components/form/examples/array-item-controls-schema.ts
  • src/components/form/examples/array-item-controls-form.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/wrap-multiple-jsx-elements-in-host-not-in-array.mdc)

When returning multiple JSX elements from the render method, never wrap them in an array literal. Instead, always wrap them in the special <Host> element. When there is already a single top-level element, it does not have to be wrapped in <Host>.

Files:

  • src/components/form/form.tsx
  • src/components/form/examples/array-item-controls-form.tsx

⚙️ CodeRabbit configuration file

**/*.tsx: Our .tsx files are typically using StencilJS, not React. When a developer wants to return multiple top-level JSX elements from the render method, they will sometimes wrap them in an array literal. In these cases, rather than recommending they add key properties to the elements, recommend removing the hardcoded array literal. Recommend wrapping the elements in StencilJS's special <Host> element.

Files:

  • src/components/form/form.tsx
  • src/components/form/examples/array-item-controls-form.tsx
**/*.{tsx,scss}

⚙️ CodeRabbit configuration file

**/*.{tsx,scss}: Almost all our components use shadow-DOM. Therefore, we have no need of BEM-style class names in our CSS.

Files:

  • src/components/form/form.tsx
  • src/components/form/examples/array-item-controls-form.tsx
src/components/**/*.tsx

⚙️ CodeRabbit configuration file

src/components/**/*.tsx: When contributors add new props to existing components in the lime-elements repository, they should always add documentation examples that demonstrate the new prop's usage and explain how it works. This helps with user adoption, feature discoverability, and maintains comprehensive documentation.

Files:

  • src/components/form/form.tsx
  • src/components/form/examples/array-item-controls-form.tsx
🧠 Learnings (9)
📓 Common learnings
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3638
File: src/components/radio-button-group/radio-button-group.tsx:91-91
Timestamp: 2025-08-12T14:01:27.846Z
Learning: The `limel-radio-button-group` component allows deselection of radio buttons (unlike native radio buttons), which improves UX by letting users leave questions unanswered, but diverges from standard radio button behavior expectations.
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3581
File: src/components/chip-set/chip-set.tsx:626-626
Timestamp: 2025-07-02T12:49:21.522Z
Learning: When contributors add new props to existing components in the lime-elements repository, they should always add documentation examples that demonstrate the new prop's usage and explain how it works. This helps with user adoption, feature discoverability, and maintains comprehensive documentation.
📚 Learning: 2025-08-26T08:42:17.994Z
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3628
File: src/components/list-item/list-item.tsx:316-321
Timestamp: 2025-08-26T08:42:17.994Z
Learning: In src/components/list-item/list-item.tsx, the RadioButtonTemplate and CheckboxTemplate components are used purely for visualization and receive their checked state from the parent component's selected prop. The actual interaction is handled by a centralized onClick handler on the Host element, making the entire list item clickable. Adding onChange handlers to these templates would be redundant and potentially problematic.

Applied to files:

  • src/components/form/templates/array-field.ts
  • src/components/form/templates/array-field-collapsible-item.ts
  • src/components/form/templates/array-field-simple-item.ts
📚 Learning: 2025-07-02T12:49:21.522Z
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3581
File: src/components/chip-set/chip-set.tsx:626-626
Timestamp: 2025-07-02T12:49:21.522Z
Learning: When contributors add new props to existing components in the lime-elements repository, they should always add documentation examples that demonstrate the new prop's usage and explain how it works. This helps with user adoption, feature discoverability, and maintains comprehensive documentation.

Applied to files:

  • src/components/form/form.tsx
📚 Learning: 2025-04-16T14:14:18.253Z
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3530
File: src/components/text-editor/examples/text-editor-composite.tsx:4-7
Timestamp: 2025-04-16T14:14:18.253Z
Learning: For lime-elements, example files should be self-contained and avoid importing internal implementation details. This includes not importing types from internal files like '../types.ts', especially those marked with beta. Duplicating simple type definitions in example files is preferred over importing internal types that may change.

Applied to files:

  • src/components/form/form.tsx
📚 Learning: 2025-04-16T14:14:18.253Z
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3530
File: src/components/text-editor/examples/text-editor-composite.tsx:4-7
Timestamp: 2025-04-16T14:14:18.253Z
Learning: For lime-elements, example files should be self-contained and avoid importing internal implementation details. Example files should only import public exports from 'limetech/lime-elements' or use relative imports for other files within the examples folder. Duplicating simple type definitions in example files is preferred over importing internal types.

Applied to files:

  • src/components/form/form.tsx
📚 Learning: 2025-03-04T14:27:29.714Z
Learnt from: adrianschmidt
Repo: Lundalogik/lime-elements PR: 3464
File: src/components/text-editor/prosemirror-adapter/plugins/image/inserter.ts:1-11
Timestamp: 2025-03-04T14:27:29.714Z
Learning: In example components (typically found in `src/components/*/examples/`), imports of lime-elements exports should use `limetech/lime-elements` instead of relative paths. This is because example components aren't included in type declarations and are used in documentation to show developers how to properly use lime-elements components.

Applied to files:

  • src/components/form/form.tsx
📚 Learning: 2025-04-17T09:39:36.254Z
Learnt from: adrianschmidt
Repo: Lundalogik/lime-elements PR: 3530
File: src/components/text-editor/examples/text-editor-composite.tsx:4-7
Timestamp: 2025-04-17T09:39:36.254Z
Learning: For lime-elements, example files should import types from the public API using 'limetech/lime-elements' rather than defining duplicate types locally. This includes types like `EditorUiType` which are part of the component's public API.

Applied to files:

  • src/components/form/form.tsx
📚 Learning: 2025-08-21T15:57:46.879Z
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3628
File: src/components/list-item/examples/list-item-actions.tsx:40-63
Timestamp: 2025-08-21T15:57:46.879Z
Learning: The examples in src/components/list-item/examples/ are for internal usage and verification, not for external developers. The actual consumers of limel-list-item are other internal components like limel-list or limel-menu-list. These examples should be taken with a pinch of salt regarding semantic correctness and accessibility, as the proper implementation will be handled by the consuming components.

Applied to files:

  • src/components/form/form.tsx
📚 Learning: 2025-08-12T14:01:27.846Z
Learnt from: Kiarokh
Repo: Lundalogik/lime-elements PR: 3638
File: src/components/radio-button-group/radio-button-group.tsx:91-91
Timestamp: 2025-08-12T14:01:27.846Z
Learning: The `limel-radio-button-group` component allows deselection of radio buttons (unlike native radio buttons), which improves UX by letting users leave questions unanswered, but diverges from standard radio button behavior expectations.

Applied to files:

  • src/components/form/form.tsx
🧬 Code graph analysis (5)
src/components/form/templates/array-field.ts (1)
src/components/form/templates/array-field-simple-item.ts (1)
  • SimpleItemTemplate (13-128)
src/components/form/examples/array-item-controls-schema.ts (1)
src/components/form/form.types.ts (1)
  • FormSchema (341-678)
src/components/form/templates/array-field-collapsible-item.ts (2)
src/components/collapsible-section/action.ts (1)
  • Action (4-9)
src/components/form/templates/types.ts (1)
  • Runnable (16-18)
src/components/form/templates/array-field-simple-item.ts (1)
src/components/form/templates/types.ts (1)
  • ArrayFieldItem (10-10)
src/components/form/examples/array-item-controls-form.tsx (2)
src/components/form/examples/array-item-controls-schema.ts (2)
  • ArrayItemControlsFormData (9-12)
  • baseSchema (14-64)
src/components/form/form.types.ts (1)
  • FormSchema (341-678)
🪛 Biome (2.1.2)
src/components/form/examples/array-item-controls-form.tsx

[error] 51-53: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 65-69: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 70-70: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Docs / Publish Docs
  • GitHub Check: Test
  • GitHub Check: Build
🔇 Additional comments (17)
src/components/form/form.tsx (1)

45-45: LGTM!

The example component reference is correctly added and aligns with the new array item controls feature demonstrated in the corresponding example file.

src/components/form/form.types.ts (1)

218-228: LGTM!

The new properties allowItemReorder and allowItemRemoval are well-documented and follow TypeScript conventions. The example component limel-example-form-array-item-controls appropriately demonstrates their usage, satisfying the requirement for documentation examples when adding new props to components.

Based on learnings

src/components/form/templates/array-field.ts (3)

9-12: LGTM!

The internal ArrayItemControls interface cleanly encapsulates the per-item control flags for removal and reordering.


71-78: LGTM!

The getItemControls() method correctly derives controls from the schema's lime options with sensible defaults. The logic !== false ensures backward compatibility by defaulting to enabled when not explicitly disabled.


45-69: LGTM!

The renderItem method correctly computes controls once per item and appropriately passes allowItemRemoval and allowItemReorder to both CollapsibleItemTemplate and SimpleItemTemplate.

src/components/form/examples/array-item-controls-schema.ts (1)

1-64: LGTM!

The schema definition is well-structured with appropriate types and defaults. The import from @limetech/lime-elements follows the coding guideline for example files. The placeholder lime: {} objects on lines 25 and 61 are appropriately populated dynamically by the consuming example component.

As per coding guidelines

src/components/form/templates/array-field-collapsible-item.ts (3)

33-43: LGTM!

The new props allowItemRemoval and allowItemReorder are well-documented and appropriately typed as required booleans.


45-45: LGTM!

The class signature is correctly updated to be strongly typed with React.Component<CollapsibleItemProps>.


101-132: LGTM!

The setActions method correctly implements conditional action assembly based on the allowItemReorder and allowItemRemoval flags, ensuring only permitted actions are exposed to users.

src/components/form/templates/array-field-simple-item.ts (5)

4-9: LGTM!

The SimpleItemProps interface is correctly extended with the new control flags allowItemRemoval and allowItemReorder.


13-26: LGTM!

The class signature is properly updated and the button references are correctly typed as optional. The cleanup in componentWillUnmount properly releases all button references.


28-43: LGTM!

The render method correctly conditionally renders reorder and removal buttons based on the allowItemReorder and allowItemRemoval props.


45-73: LGTM!

The button render methods are correctly updated to use ref callbacks (setRemoveButton, setMoveUpButton, setMoveDownButton) for managing button references and event listeners.


90-127: LGTM!

The ref callback methods (setRemoveButton, setMoveUpButton, setMoveDownButton) correctly manage event listener lifecycle by cleaning up old listeners before adding new ones. This pattern is more React-idiomatic than the previous componentDidMount approach and handles conditional rendering properly.

src/components/form/examples/array-item-controls-form.tsx (3)

1-48: LGTM!

The component setup, imports, documentation, and state management are well-structured. The imports correctly use @limetech/lime-elements as per the coding guidelines for example files.

As per coding guidelines


74-86: LGTM!

The event handlers correctly toggle state and regenerate the schema to reflect the control changes.


88-117: LGTM!

The createSchema method correctly derives a new schema from baseSchema and dynamically injects the allowItemReorder and allowItemRemoval flags into the lime options for both tasks and missions arrays, enabling the feature demonstration.

@Kiarokh Kiarokh force-pushed the form-allow-item-removal-&-reorder branch from 80a8076 to 670fcc1 Compare November 19, 2025 12:19
Comment on lines 37 to 41
this.props.allowItemReorder
? this.renderMoveDownButton(item)
: null,
this.props.allowItemReorder ? this.renderMoveUpButton(item) : null,
this.props.allowItemReorder ? this.renderMoveDownButton(item) : null
this.props.allowItemRemoval ? this.renderRemoveButton(item) : null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before this change, the UI looked like this:
Screenshot 2025-11-19 at 13 19 46

Copy link
Contributor

@devbymadde devbymadde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! :)

@Kiarokh Kiarokh force-pushed the form-allow-item-removal-&-reorder branch from 670fcc1 to 70bf02e Compare November 20, 2025 14:57
@Kiarokh Kiarokh enabled auto-merge (rebase) November 20, 2025 14:57
@Kiarokh
Copy link
Contributor Author

Kiarokh commented Nov 20, 2025

@paulinewahle FYI
Here is a candidate to update the What's new page. In case you wanna add it to your todo list. There is also a dedicated new example for thefeature.

Copy link
Contributor

@adrianschmidt adrianschmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes to external API approved.

@Kiarokh Kiarokh merged commit 5f8781e into main Nov 21, 2025
12 checks passed
@Kiarokh Kiarokh deleted the form-allow-item-removal-&-reorder branch November 21, 2025 12:55
@lime-opensource
Copy link
Collaborator

🎉 This PR is included in version 38.30.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants