Skip to content

Commit

Permalink
Merge pull request #44 from getpingback/feat/variable-input-custom-fi…
Browse files Browse the repository at this point in the history
…elds

feat(variable-input): add custom fields and combobox
  • Loading branch information
pepeladeira authored Nov 28, 2024
2 parents 643c46f + e127035 commit 91827bb
Show file tree
Hide file tree
Showing 5 changed files with 380 additions and 151 deletions.
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,33 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [0.0.265](https://github.com/getpingback/ui/compare/v0.0.264...v0.0.265) (2024-11-27)


### Bug Fixes

* **variable-input:** initial content ([9a44ec0](https://github.com/getpingback/ui/commits/9a44ec0db6bc2e8e47056ec24e8939eb21c5b897))

### [0.0.263](https://github.com/getpingback/ui/compare/v0.0.262...v0.0.263) (2024-11-27)


### Bug Fixes

* **variable-input:** reset search on close ([ff0075e](https://github.com/getpingback/ui/commits/ff0075e17bd53aac5ceca5a8f7ea73cb5f85684f))

### [0.0.261](https://github.com/getpingback/ui/compare/v0.0.260...v0.0.261) (2024-11-27)


### Features

* **variable-input:** add custom fields and combobox ([3e89a07](https://github.com/getpingback/ui/commits/3e89a07602d029ad5a8ee5490631503a52706c9a))


### Bug Fixes

* change selection scope ([ec3c5b3](https://github.com/getpingback/ui/commits/ec3c5b31c39522303b26f2ca136d96c819806c8b))
* **variable-input:** remove unused components ([844a5db](https://github.com/getpingback/ui/commits/844a5db2bd55b9fbdebd73dfcc14c1786cc3ae1a))

### [0.0.260](https://github.com/getpingback/ui/compare/v0.0.257...v0.0.260) (2024-11-27)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@getpingback/ui",
"author": "Pingback Team",
"version": "0.0.260",
"version": "0.0.266",
"license": "MIT",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
47 changes: 29 additions & 18 deletions src/components/variable-input/variable-input.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,55 @@
import type { Meta, StoryObj } from "@storybook/react";
import type { Meta, StoryObj } from '@storybook/react';

import { VariableInput } from "./variable-input";
import { VariableInput } from './variable-input';

const meta = {
title: "Components/VariableInput",
title: 'Components/VariableInput',
component: VariableInput,
parameters: {},

tags: ["autodocs"],
tags: ['autodocs'],

argTypes: {},
argTypes: {}
} satisfies Meta<typeof VariableInput>;

export default meta;
type Story = StoryObj<typeof meta>;

const options = [
{ label: "Email", value: "email" },
{ label: "Name", value: "name" },
{ label: "Phone", value: "phone" },
{
heading: 'Common Variables',
items: [
{ label: 'Email', value: 'email' },
{ label: 'Name', value: 'name' },
{ label: 'Phone', value: 'phone' }
]
},
{
heading: 'Custom Variables',
items: [{ label: 'Custom Variable', value: 'customVariable' }]
}
];

export const Default: Story = {
args: {
options,
},
options
}
};

export const WithInputProps: Story = {
args: {
label: "URL",
placeholder: "https://www.example.com",
helperText: "Enter the URL of the page you want to redirect to",
options,
},
label: 'URL',
placeholder: 'https://www.example.com',
helperText: 'Enter the URL of the page you want to redirect to',
options
}
};

export const WithInitialContent: Story = {
args: {
initialContent: "Hello {{name}}! How are you?",
options,
},
label: 'Expression',
placeholder: 'Enter the expression',
initialContent: 'Hello {{name}}! How are you?',
options
}
};
98 changes: 74 additions & 24 deletions src/components/variable-input/variable-input.test.tsx
Original file line number Diff line number Diff line change
@@ -1,64 +1,114 @@
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import { VariableInput } from "./variable-input";
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { VariableInput } from './variable-input';

describe("VariableInput Component", () => {
describe('VariableInput Component', () => {
const options = [
{ label: "Variable 1", value: "var1" },
{ label: "Variable 2", value: "var2" },
{
heading: 'Common Variables',
items: [
{ label: 'Email', value: 'email' },
{ label: 'Name', value: 'name' },
{ label: 'Phone', value: 'phone' }
]
},
{
heading: 'Custom Variables',
items: [{ label: 'Custom Variable', value: 'customVariable' }]
}
];

it("should render with default props and open dropdown on trigger click", () => {
it('should render with default props and open dropdown on trigger click', () => {
const { getByTestId, getByText } = render(<VariableInput options={options} />);

const triggerButton = getByTestId("variable-input-trigger");
const triggerButton = getByTestId('variable-input-trigger');
fireEvent.click(triggerButton);

expect(getByText("Variable 1")).toBeInTheDocument();
expect(getByText("Variable 2")).toBeInTheDocument();
expect(getByText('Email')).toBeInTheDocument();
expect(getByText('Name')).toBeInTheDocument();
expect(getByText('Phone')).toBeInTheDocument();
expect(getByText('Custom Variable')).toBeInTheDocument();
});

it("should call onChangeContent when text is input", () => {
it('should call onChangeContent when text is input', () => {
const handleChangeContent = jest.fn();
const { container } = render(<VariableInput options={options} onChangeContent={handleChangeContent} />);

const editor = container.querySelector("[contenteditable='true']");
if (editor) {
fireEvent.input(editor, { target: { textContent: "Hello" } });
expect(handleChangeContent).toHaveBeenCalledWith("Hello");
fireEvent.input(editor, { target: { textContent: 'Hello' } });
expect(handleChangeContent).toHaveBeenCalledWith('Hello');
}
});

it("should call onSelect when a variable is selected", () => {
it('should call onSelect when a variable is selected', () => {
const handleSelect = jest.fn();
const { getByText, getByTestId } = render(<VariableInput options={options} onSelect={handleSelect} />);
const { getByText, getByTestId } = render(<VariableInput options={options} onSelectVariable={handleSelect} />);

const triggerButton = getByTestId("variable-input-trigger");
const triggerButton = getByTestId('variable-input-trigger');
fireEvent.click(triggerButton);

fireEvent.click(getByText("Variable 1"));
expect(handleSelect).toHaveBeenCalledWith("var1");
fireEvent.click(getByText('Email'));
expect(handleSelect).toHaveBeenCalledWith('email');
});

it("should display placeholder when not focused and empty", () => {
const { container } = render(<VariableInput options={options} placeholder='Enter text' />);
it('should display placeholder when not focused and empty', () => {
const { container } = render(<VariableInput options={options} placeholder="Enter text" />);

const editor = container.querySelector("[contenteditable='true']");
if (editor) {
expect(editor.innerHTML).toContain("Enter text");
expect(editor.innerHTML).toContain('Enter text');
}
});

it("should prevent editing of variable spans", () => {
it('should prevent editing of variable spans', () => {
const { container } = render(<VariableInput options={options} />);
const editor = container.querySelector("[contenteditable='true']");

if (editor) {
fireEvent.input(editor, { target: { innerHTML: '<span data-variable="var1">Variable 1</span>' } });

fireEvent.keyDown(editor, { key: "Backspace" });
fireEvent.keyDown(editor, { key: 'Backspace' });

expect(editor.innerHTML).toContain('Variable 1');
}
});

it('should filter variables when text is typed in the search input', () => {
const { getByTestId, queryByText } = render(<VariableInput options={options} />);

const triggerButton = getByTestId('variable-input-trigger');
fireEvent.click(triggerButton);

const searchInput = getByTestId('variable-input-search-input');
fireEvent.change(searchInput, { target: { value: 'email' } });

expect(queryByText('Email')).toBeInTheDocument();
expect(queryByText('Name')).not.toBeInTheDocument();
expect(queryByText('Phone')).not.toBeInTheDocument();
expect(queryByText('Custom Variable')).not.toBeInTheDocument();
});

it('should show message when no variables are found in the search', () => {
const { getByTestId, getByText } = render(<VariableInput options={options} />);

const triggerButton = getByTestId('variable-input-trigger');
fireEvent.click(triggerButton);

const searchInput = getByTestId('variable-input-search-input');
fireEvent.change(searchInput, { target: { value: 'xyz' } });

expect(editor.innerHTML).toContain("Variable 1");
expect(getByText('No results found')).toBeInTheDocument();
});

it('should prioritize initialContent over placeholder', () => {
const initialContent = 'Initial content';
const { container } = render(<VariableInput options={options} initialContent={initialContent} placeholder="Placeholder" />);

const editor = container.querySelector("[contenteditable='true']");
if (editor) {
expect(editor.innerHTML).toBe(initialContent);
expect(editor.innerHTML).not.toBe('Placeholder');
}
});
});
Loading

0 comments on commit 91827bb

Please sign in to comment.