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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
46 changes: 45 additions & 1 deletion .github/instructions/html.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ export interface ButtonProps {

**Naming Convention**:
- Use descriptive file names: `card-normal.tsx`, `card-horizontal.tsx`
- Export from component's `index.ts`
- Prefer `[component]-normal.tsx` when the template represents the default rendering of a component; otherwise use a descriptive template name (e.g., `text-button.tsx`, `icon-button.tsx`)
- Add exports to component's `index.ts` for external package consumers (but don't import FROM index.ts within the package)

**Example**:
```typescript
Expand Down Expand Up @@ -115,6 +116,9 @@ export default () => (
- Export all templates
- Export test utilities
- Maintain clean import paths
- **NOT for internal imports** - tests, demos, and templates should use direct file imports

**Internal Usage Rule**: Files within `packages/html/src/` should import directly from specific files, not from index files. Index files exist only to define the public API for external consumers.

## Coding Standards

Expand All @@ -134,6 +138,46 @@ export default () => (
- Specs: kebab-case (` button.spec.tsx`)
- CSS classes: BEM with `k-` prefix (`k-button`, `k-button-solid`)

## Development Workflow

The HTML package follows a modular architecture where components are built from discrete files:

1. **Spec files** (`.spec.tsx`) - Define component interfaces and props
2. **Template files** (`templates/*.tsx`) - Implement reusable UI patterns
3. **Test files** (`tests/*.tsx`) - Create visual test scenarios
4. **Index files** (`index.ts`) - Export public API for external consumers

**Internal Import Pattern**: Within the package, files import directly from specific files to avoid bundling unnecessary code. For example, a test file imports `from '../button.spec'` rather than `from '..'` to ensure only the needed code is included.

**External Import Pattern**: External consumers use the package via `import { Button } from '@progress/kendo-theme-html'`, which uses the index files.

This separation keeps bundle sizes minimal and enables tree-shaking for downstream consumers.

## Important Guidelines

⚠️ **Bundle Size Optimization**: Always import from specific component files, NOT from index files.

## Code Review Guidelines

When reviewing code changes in the HTML package, **always check imports** and report violations:

### Import Violations to Flag:
- ❌ `from '../../button'` or `from "../../button"` - missing file name (uses index)
- ❌ `from '../../button/'` or `from "../../button/"` - trailing slash (uses index)
- ❌ `from '../../button/index'` or `from "../../button/index"` - explicit index import
- ❌ `from '..'` or `from ".."` - parent directory (uses index)
- ❌ `from '../'` or `from "../"` - parent directory with trailing slash (uses index)
- ❌ `from '.'` or `from "."` - current directory (uses index)
- ❌ `from './'` or `from "./"` - current directory with trailing slash (uses index)
- ✅ `from '../../button/button.spec'` or `from "../../button/button.spec"` - correct specific file import
- ✅ `from '../wizard-steps'` or `from "../wizard-steps"` - correct direct file import (not a directory)

**Required Check**: For every import from `../../[component-name]` without a file path, verify that the imported path is:
1. A **specific file** (e.g., `button.spec`, `toolbar-popup.spec`)
2. NOT a **directory** that contains an index file

Report any violations with: "Bundle size issue: Import uses barrel file. Change `from '../../X'` to `from '../../X/X.spec'` or specific file."

## Build Commands

```bash
Expand Down
20 changes: 19 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,25 @@ module.exports = [
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": ["error", {"varsIgnorePattern": "^_"}],
"no-unused-vars": "off",
"no-undef": 'off'
"no-undef": 'off',
"no-restricted-imports": ["error", {
"patterns": [
{
"group": ["*/index", "*/index.ts", "*/index.tsx", "**/index", "**/index.ts", "**/index.tsx"],
"message": "Import from specific files instead of index to reduce bundle size. Use the specific component file (e.g., '../../button/button.spec' instead of '../../button/index')."
}
]
}]
}
},
{
name: "html-components-index-exception",
files: [
"packages/html/src/index.ts",
"packages/html/src/*/index.ts"
],
rules: {
"no-restricted-imports": "off"
}
}
]
4 changes: 2 additions & 2 deletions packages/html/src/action-buttons/tests/action-buttons.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ActionButtons } from '../../action-buttons';
import { Button } from '../../button';
import { ActionButtons } from '../../action-buttons/action-buttons.spec';
import { Button } from '../../button/button.spec';


const styles = `
Expand Down
2 changes: 1 addition & 1 deletion packages/html/src/action-sheet/demos/action-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ActionSheetHeader } from '../actionsheet-header';
import { ActionSheetFooter } from '../actionsheet-footer';
import { ActionSheetItems } from '../actionsheet-items';
import { ActionSheetItem } from '../actionsheet-item';
import { Button } from '../../button';
import { Button } from '../../button/button.spec';

const options = ActionSheet.options;
const states = ActionSheet.states;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { ActionSheet, ActionSheetHeader, ActionSheetItem, ActionSheetItems } from '../../action-sheet';
import { ActionSheet } from '../../action-sheet/action-sheet.spec';
import { ActionSheetHeader } from '../actionsheet-header';
import { ActionSheetItems } from '../actionsheet-items';
import { ActionSheetItem } from '../actionsheet-item';

export const ActionSheetNormal = ({ title = "Select item", ...other }) => (
<ActionSheet
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { ActionSheetItems, ActionSheetItem, ActionSheetNormal, ActionSheetFooter } from '..';
import { Button } from '../../button';
import { ActionSheetItem } from '../actionsheet-item';
import { ActionSheetItems } from '../actionsheet-items';
import { ActionSheetFooter } from '../actionsheet-footer';
import { ActionSheetNormal } from '../templates/action-sheet-normal';
import { Button } from '../../button/button.spec';

const styles = `
#test-area > section {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { ActionSheetItems, ActionSheetItem, ActionSheetNormal, ActionSheetHeader } from '..';
import { Button } from '../../button';
import { ActionSheetItem } from '../actionsheet-item';
import { ActionSheetItems } from '../actionsheet-items';
import { ActionSheetHeader } from '../actionsheet-header';
import { ActionSheetNormal } from '../templates/action-sheet-normal';
import { Button } from '../../button/button.spec';

const styles = `
#test-area > section {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ActionSheetItems, ActionSheetItem, ActionSheetNormal, ActionSheetFooter, ActionSheetHeader } from '..';
import { Button } from '../../button';
import { ActionSheetItem } from '../actionsheet-item';
import { ActionSheetItems } from '../actionsheet-items';
import { ActionSheetHeader } from '../actionsheet-header';
import { ActionSheetFooter } from '../actionsheet-footer';
import { ActionSheetNormal } from '../templates/action-sheet-normal';
import { Button } from '../../button/button.spec';


const styles = `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ActionSheet, ActionSheetHeader } from '..';
import { Button } from '../../button';
import { CalendarInfiniteNormal } from '../../calendar';
import { ActionSheet } from '../action-sheet.spec';
import { ActionSheetHeader } from '../actionsheet-header';
import { Button } from '../../button/button.spec';
import { CalendarInfiniteNormal } from '../../calendar/templates/calendar-infinite-normal';


const styles = `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ActionSheet, ActionSheetHeader } from '../../action-sheet';
import { Button } from '../../button';
import { CalendarNormal } from '../../calendar';
import { ActionSheet } from '../action-sheet.spec';
import { ActionSheetHeader } from '../actionsheet-header';
import { Button } from '../../button/button.spec';
import { CalendarNormal } from '../../calendar/templates/calendar-normal';


const styles = `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import { ActionSheet, ActionSheetFooter, ActionSheetHeader } from '../../action-sheet';
import { Button } from '../../button';
import { DataTable, TableBody, TableFooter, TableGroupStickyHeader, TableHeader, TableList, TableListGroupRow, TableListRow, TableListTd, TableListTh, TableRow, TableTh, TableThead } from '../../table';
import { ActionSheet } from '../../action-sheet/action-sheet.spec';
import { ActionSheetHeader } from '../../action-sheet/actionsheet-header';
import { ActionSheetFooter } from '../../action-sheet/actionsheet-footer';
import { Button } from '../../button/button.spec';
import { DataTable } from '../../table/data-table.spec';
import { TableBody } from '../../table/table-body';
import { TableFooter } from '../../table/table-footer.spec';
import { TableGroupStickyHeader } from '../../table/table-group-sticky-header';
import { TableHeader } from '../../table/table-header.spec';
import { TableList } from '../../table/table-list.spec';
import { TableListGroupRow } from '../../table/table-list-group-row';
import { TableListRow } from '../../table/table-list-row';
import { TableListTd } from '../../table/table-list-td';
import { TableListTh } from '../../table/table-list-th';
import { TableRow } from '../../table/table-row';
import { TableTh } from '../../table/table-th.spec';
import { TableThead } from '../../table/table-thead';


const styles = `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { ActionSheet, ActionSheetFooter, ActionSheetHeader } from '../../action-sheet';
import { Button } from '../../button';
import { CalendarNormal } from '../../calendar';
import { TimeSelector, TimeSelectorHeader } from '../../time-selector';
import { ActionSheet } from '../../action-sheet/action-sheet.spec';
import { ActionSheetHeader } from '../../action-sheet/actionsheet-header';
import { ActionSheetFooter } from '../../action-sheet/actionsheet-footer';
import { Button } from '../../button/button.spec';
import { CalendarNormal } from '../../calendar/templates/calendar-normal';
import { TimeSelector } from '../../time-selector/time-selector.spec';
import { TimeSelectorHeader } from '../../time-selector/time-selector-header';


const styles = `
Expand Down
12 changes: 9 additions & 3 deletions packages/html/src/action-sheet/tests/action-sheet-list.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { ActionSheet, ActionSheetFooter, ActionSheetHeader } from '../../action-sheet';
import { Button } from '../../button';
import { List, ListContent, ListGroupItem, ListItem, ListUl } from '../../list';
import { ActionSheet } from '../../action-sheet/action-sheet.spec';
import { ActionSheetHeader } from '../../action-sheet/actionsheet-header';
import { ActionSheetFooter } from '../../action-sheet/actionsheet-footer';
import { Button } from '../../button/button.spec';
import { List } from '../../list/list.spec';
import { ListContent } from '../../list/list-content';
import { ListGroupItem } from '../../list/list-group-item';
import { ListItem } from '../../list/list-item.spec';
import { ListUl } from '../../list/list-ul';


const styles = `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ActionSheetLeft, ActionSheetRight, ActionSheetTop, ActionSheetNormal } from '../../action-sheet';

import { ActionSheetLeft } from '../../action-sheet/templates/action-sheet-left';
import { ActionSheetRight } from '../../action-sheet/templates/action-sheet-right';
import { ActionSheetTop } from '../../action-sheet/templates/action-sheet-top';
import { ActionSheetNormal } from '../../action-sheet/templates/action-sheet-normal';

const styles = `
#test-area {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { ActionSheet, ActionSheetFooter, ActionSheetHeader } from '../../action-sheet';
import { Button } from '../../button';
import { TimeSelector, TimeSelectorHeader } from '../../time-selector';
import { ActionSheet } from '../../action-sheet/action-sheet.spec';
import { ActionSheetHeader } from '../../action-sheet/actionsheet-header';
import { ActionSheetFooter } from '../../action-sheet/actionsheet-footer';
import { Button } from '../../button/button.spec';
import { TimeSelector } from '../../time-selector/time-selector.spec';
import { TimeSelectorHeader } from '../../time-selector/time-selector-header';


const styles = `
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ActionSheet, ActionSheetHeader } from '../../action-sheet';
import { Button } from '../../button';
import { Treeview, TreeviewItem } from '../../treeview';
import { ActionSheet } from '../../action-sheet/action-sheet.spec';
import { ActionSheetHeader } from '../../action-sheet/actionsheet-header';
import { Button } from '../../button/button.spec';
import { Treeview } from '../../treeview/treeview.spec';
import { TreeviewItem } from '../../treeview/treeview-item.spec';


const styles = `
Expand Down
12 changes: 9 additions & 3 deletions packages/html/src/action-sheet/tests/action-sheet-views.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Button } from "../../button";
import { ActionSheetNormal, ActionSheetHeader, ActionSheetFooter, ActionSheetView } from "../../action-sheet";
import { ColumnMenuNormal, ColumnMenuItemWrapper, ColumnMenuItem, ColumnMenuExpander } from "../../column-menu";
import { Button } from "../../button/button.spec";
import { ActionSheetNormal } from "../templates/action-sheet-normal";
import { ActionSheetHeader } from "../actionsheet-header";
import { ActionSheetFooter } from "../actionsheet-footer";
import { ActionSheetView } from "../actionsheet-view";
import { ColumnMenuNormal } from "../../column-menu/templates/column-menu-normal";
import { ColumnMenuItemWrapper } from "../../column-menu/column-menu-item-wrapper";
import { ColumnMenuItem } from "../../column-menu/column-menu-item.spec";
import { ColumnMenuExpander } from "../../column-menu/column-menu-expander.spec";

const styles = `
#test-area {
Expand Down
8 changes: 6 additions & 2 deletions packages/html/src/action-sheet/tests/action-sheet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ActionSheetItems, ActionSheetItem, ActionSheetNormal, ActionSheetFooter, ActionSheetHeader } from '..';
import { Button } from '../../button';
import { ActionSheetItem } from '../actionsheet-item';
import { ActionSheetItems } from '../actionsheet-items';
import { ActionSheetHeader } from '../actionsheet-header';
import { ActionSheetFooter } from '../actionsheet-footer';
import { ActionSheetNormal } from '../templates/action-sheet-normal';
import { Button } from '../../button/button.spec';


const styles = `
Expand Down
7 changes: 4 additions & 3 deletions packages/html/src/appbar/demos/appbar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Appbar, KendoAppbarProps } from '../appbar.spec';
import { AppbarSection } from '../appbar-section';
import { AppbarNormal } from '../templates/appbar-normal';
import { AvatarImage } from '../../avatar';
import { IconButton, TextButton } from '../../button';
import { TextboxNormal } from '../../textbox';
import { AvatarImage } from '../../avatar/templates/avatar-image';
import { IconButton } from '../../button/templates/icon-button';
import { TextButton } from '../../button/templates/text-button';
import { TextboxNormal } from '../../textbox/templates/textbox-normal';

const options = { ...Appbar.options };
const states = Appbar.states;
Expand Down
5 changes: 3 additions & 2 deletions packages/html/src/appbar/templates/appbar-normal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Appbar, AppbarSection } from '../../appbar';
import { Icon } from '../../icon';
import { Appbar } from '../appbar.spec';
import { AppbarSection } from '../appbar-section';
import { Icon } from '../../icon/icon.spec';

export const AppbarNormal = (props) => (
<Appbar children={
Expand Down
8 changes: 5 additions & 3 deletions packages/html/src/appbar/tests/appbar-rtl.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Appbar, AppbarNormal, AppbarSection } from '../../appbar';
import { Icon } from '../../icon';
import { Textbox } from '../../textbox';
import { Appbar } from '../appbar.spec';
import { AppbarNormal } from '../templates/appbar-normal';
import { AppbarSection } from '../appbar-section';
import { Icon } from '../../icon/icon.spec';
import { Textbox } from '../../textbox/textbox.spec';


const styles = `
Expand Down
8 changes: 5 additions & 3 deletions packages/html/src/appbar/tests/appbar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Appbar, AppbarNormal, AppbarSection } from '../../appbar';
import { Icon } from '../../icon';
import { Textbox } from '../../textbox';
import { Appbar } from '../appbar.spec';
import { AppbarNormal } from '../templates/appbar-normal';
import { AppbarSection } from '../appbar-section';
import { Icon } from '../../icon/icon.spec';
import { Textbox } from '../../textbox/textbox.spec';


const styles = `
Expand Down
10 changes: 6 additions & 4 deletions packages/html/src/autocomplete/demos/autocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { KendoAutocompleteProps } from '../autocomplete.spec';
import { AutocompleteNormal } from '../templates/autocomplete-normal';
import { Textbox } from '../../textbox';
import { Icon } from '../../icon';
import { TextButton } from '../../button';
import { List, ListContent, ListItem } from '../../list';
import { Textbox } from '../../textbox/textbox.spec';
import { Icon } from '../../icon/icon.spec';
import { TextButton } from '../../button/templates/text-button';
import { List } from '../../list/list.spec';
import { ListContent } from '../../list/list-content';
import { ListItem } from '../../list/list-item.spec';

const states = Textbox.states;
const defaults = Textbox.defaultOptions;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import Autocomplete from "../autocomplete.spec";
import { List, ListContent, ListCustomValue, ListItem } from "../../list";
import { List } from '../../list/list.spec';
import { ListContent } from '../../list/list-content';
import { ListItem } from '../../list/list-item.spec';
import { ListCustomValue } from '../../list/list-custom-value';

export const AutocompleteCustomValue = ({ value="Custom value", ...other }: any) => (
<Autocomplete value={value}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import Autocomplete from "../autocomplete.spec";
import { List, ListContent, ListUl, ListItem, ListGroupItem, ListCustomValue } from "../../list";
import { List } from "../../list/list.spec";
import { ListContent } from "../../list/list-content";
import { ListUl } from "../../list/list-ul";
import { ListItem } from "../../list/list-item.spec";
import { ListGroupItem } from "../../list/list-group-item";
import { ListCustomValue } from "../../list/list-custom-value";

export const AutocompleteGroupingModernCustomValue = ({ value="Custom value", ...other }: any) => (
<Autocomplete value={value}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import Autocomplete from "../autocomplete.spec";
import { List, ListContent, ListUl, ListItem, ListGroupItem } from "../../list";
import { List } from "../../list/list.spec";
import { ListContent } from "../../list/list-content";
import { ListUl } from "../../list/list-ul";
import { ListItem } from "../../list/list-item.spec";
import { ListGroupItem } from "../../list/list-group-item";

export const AutocompleteGrouping = (props) => (
<Autocomplete
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import Autocomplete from "../autocomplete.spec";
import { List, ListContent, ListItem } from "../../list";
import { List } from "../../list/list.spec";
import { ListContent } from "../../list/list-content";
import { ListItem } from "../../list/list-item.spec";

export const AutocompletePopup = (props) => (
<Autocomplete
Expand Down
Loading
Loading