Skip to content
Draft
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
64 changes: 64 additions & 0 deletions .cursor/rules/svelte-migration.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
description:
globs:
alwaysApply: false
---

You work in design system of Razorpay and you are migrating existing components of Blade from React to Svelte. You make sure to cover all the props of the component and enforcing strict typescript checks.

- You refer to existing components for expected props and HTML structure
- You understand the common props that we normally use, compound component structure that we normally use and follow WISIWYG (What You See is What You Get) Philosophy.
- Before writing the component refer to the corresponding React component written in - `packages/blade/src/components` folder
- Wherever you are unsure about some practice, just ask for confirmation
- Before writing the component, you discuss the approach on how you are writing the component and only write post confirmation
- The API structure of the components should clean and easier to understand and integrate
- Some component might be using another component like Link or Button component uses Icon or BaseText. Wherever this case is there confirm whether to make a migration for that or not for the imported components like Icons
Don't use createEventDispatcher for event handlers like on:click etc. Instead use a prop based mechanism expect and pass a prop
- Any utility function like - `packages/blade/src/utils/makeBorderSize/index.ts` should be placed in blade core util directory - `packages/blade-core/src/utils` and not within the blade-svelte directory.
- Whenever any utility import is encountered check in - `packages/blade-core/src/utils` directory, if the util file is not present or same function is not present ask for a confirmation before adding.

## Blade Component Svelte Guidelines
### Key Examples for references
- Study the props of the React component which you are trying to migrate to Svelte. Props should remain consistent throughout Svelte and React components.

## Directory Structure

Components should be created in the following structure:

```
packages/
└── blade-svelte/
└── src/
└── components/
├── Button/
│ ├── Button.svelte
│ └── button.css
├── Link/
│ ├── BaseLink/
│ │ ├── BaseLink.svelte
│ │ └── baseLink.css
│ └── Link.svelte
└── ... (other components)
```

### Naming Conventions
- Component directories: `PascalCase` (e.g., `Button/`, `Link/`)
- Component files: `PascalCase.svelte` (e.g., `Button.svelte`, `BaseLink.svelte`)
- CSS files: `camelCase.css` (e.g., `button.css`, `baseLink.css`)
- For nested/base components, create a subdirectory with the component name (e.g., `Link/BaseLink/`)

## Import Guidelines
- Components in svelte directory have all the blade tokens listed in `packages/blade-svelte/src/theme/theme.css`
- There is an existing example at `packages/blade-svelte/src/components/Button/` which you can refer to for any example
- You can use common function from `packages/blade-core` if needed. However do confirm before you implement

## Testing Guidelines
Add the component in packages/blade-svelte/src/App.svelte as well which will be a testing playground for testing whether component is behaving as expected or not

## Accessibility and CSS Patterns

#### Implementation Guidelines

- Always set the `disabled` attribute on the element when the component is disabled
- Use `[disabled]` attribute selector in CSS instead of adding/removing classes
- This pattern applies to buttons, links, and other interactive elements that support disabled states
6 changes: 6 additions & 0 deletions packages/blade-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
"typecheck:web": "tsc --noEmit --project tsconfig-typecheck.web.json",
"typecheck:native": "tsc --noEmit --project tsconfig-typecheck.native.json",
"build": "yarn build:generate-types && yarn build:rollup",
"build:watch": "yarn build:generate-types && yarn build:rollup:watch",
"build:generate-types": "yarn build:generate-types:web && yarn build:generate-types:native",
"build:generate-types:web": "tsc --project tsconfig-generate-types.web.json",
"build:generate-types:native": "tsc --project tsconfig-generate-types.native.json",
"build:rollup": "rollup --config rollup.config.mjs",
"build:rollup:watch": "rollup --config rollup.config.mjs --watch",
"build:rollup:web": "FRAMEWORK=REACT rollup --config rollup.config.mjs",
"build:rollup:native": "FRAMEWORK=REACT_NATIVE rollup --config rollup.config.mjs",
"test": "echo 'No tests configured yet'"
Expand Down Expand Up @@ -69,11 +71,15 @@
"exports": {
"./tokens": {
"types": "./dist/types/tokens/index.d.ts",
"development": "./dist/lib/web/development/tokens/index.js",
"production": "./dist/lib/web/production/tokens/index.js",
"default": "./dist/lib/web/production/tokens/index.js"
},
"./tokens/theme.css": "./dist/lib/web/production/tokens/theme.css",
"./utils": {
"types": "./dist/types/utils/index.d.ts",
"development": "./dist/lib/web/development/utils/index.js",
"production": "./dist/lib/web/production/utils/index.js",
"default": "./dist/lib/web/production/utils/index.js"
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/blade-core/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export * from './lodashButBetter/throttle';
export * from './hasSameObjectStructure';
export * from './isPartialMatchObjectKeys';
export * from './logger';
export * from './makeAccessible';
export * from './makeAnalyticsAttribute';
export * from './metaAttribute';
export * from './makeBezier';
export * from './platform';
export * from './types';
63 changes: 63 additions & 0 deletions packages/blade-core/src/utils/makeAccessible/accessibilityMap.ts
Copy link
Member

Choose a reason for hiding this comment

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

nice

Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { AccessibilityMap } from './types';

export const accessibilityValue = {
valueMax: 'aria-valuemax',
valueMin: 'aria-valuemin',
valueNow: 'aria-valuenow',
valueText: 'aria-valuetext',
};

export const accessibilityState = {
selected: 'aria-selected',
disabled: 'aria-disabled',
expanded: 'aria-expanded',
busy: 'aria-busy',
checked: 'aria-checked',
};

// TODO:
// accessibilityViewIsModal
export const accessibilityMap: AccessibilityMap = {
...accessibilityState,
...accessibilityValue,
activeDescendant: 'aria-activedescendant',
atomic: 'aria-atomic',
autoComplete: 'aria-autocomplete',
colCount: 'aria-colcount',
colIndex: 'aria-colindex',
colSpan: 'aria-colspan',
controls: 'aria-controls',
describedBy: 'aria-describedby',
details: 'aria-details',
errorMessage: 'aria-errormessage',
flowTo: 'aria-flowto',
hasPopup: 'aria-haspopup',
hidden: 'aria-hidden',
invalid: 'aria-invalid',
keyShortcuts: 'aria-keyshortcuts',
label: 'aria-label',
labelledBy: 'aria-labelledby',
liveRegion: 'aria-live',
modal: 'aria-modal',
multiline: 'aria-multiline',
multiSelectable: 'aria-multiselectable',
orientation: 'aria-orientation',
owns: 'aria-owns',
placeholder: 'aria-placeholder',
posInSet: 'aria-posinset',
pressed: 'aria-pressed',
readOnly: 'aria-readonly',
required: 'aria-required',
role: 'role',
roleDescription: 'aria-roledescription',
rowCount: 'aria-rowcount',
rowIndex: 'aria-rowindex',
rowSpan: 'aria-rowspan',
setSize: 'aria-setsize',
sort: 'aria-sort',
current: 'aria-current',
dropEffect: 'aria-dropeffect',
grabbed: 'aria-grabbed',
level: 'aria-level',
relevant: 'aria-relevant',
};
2 changes: 2 additions & 0 deletions packages/blade-core/src/utils/makeAccessible/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './makeAccessible';
export * from './types';
27 changes: 27 additions & 0 deletions packages/blade-core/src/utils/makeAccessible/makeAccessible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { accessibilityMap } from './accessibilityMap';
import type { AccessibilityMap, AccessibilityProps } from './types';
import { logger } from '~utils/logger';

export const makeAccessible = (props: Partial<AccessibilityProps>): Record<string, unknown> => {
const newProps: Record<string, any> = {};

// eslint-disable-next-line guard-for-in
for (const key in props) {
const propKey = key as keyof AccessibilityMap;
const propValue = props[propKey];
const accessibilityAttribute = accessibilityMap[propKey];

if (accessibilityAttribute) {
newProps[accessibilityAttribute] = propValue;
} else if (__DEV__) {
logger({
message: `No mapping found for ${propKey}. Make sure you have entered valid key`,
moduleName: 'makeAccessible',
type: 'warn',
});
}
}

return newProps;
};
Loading
Loading