npm package: @servicetitan/anvil2-codemods
Description: Anvil 2 codemod scripts
Latest version: 0.11.0

# Anvil2 Codemods

This package includes the source code for codemods created to make upgrading Anvil2 components and utilities easier.

> Inspiration is from https://github.com/carlrip/codemod-react-ts.

- [Anvil2 Codemods](#anvil2-codemods)
  - [Contributing](#contributing)
  - [Using the codemods](#using-the-codemods)
    - [Transforms](#transforms)
    - [Formatting after transforms](#formatting-after-transforms)
  - [Docs for missing transforms](#docs-for-missing-transforms)
    - [Known issues (no automated message)](#known-issues-no-automated-message)
      - [Removed import from Anvil that is used as a TypeScript Generic Parameter](#removed-import-from-anvil-that-is-used-as-a-typescript-generic-parameter)
      - [Anvil (1) Text components might need to be ran multiple times](#anvil-1-text-components-might-need-to-be-ran-multiple-times)
    - [Generic messages](#generic-messages)
      - [Component name changed and alias removed](#component-name-changed-and-alias-removed)
        - [Summary](#summary)
        - [Next steps](#next-steps)
      - [`Component.el` - No longer supported](#componentel---no-longer-supported)
        - [Summary](#summary-1)
        - [Next steps](#next-steps-1)
    - [Banner](#banner)
      - [`Banner.icon` - No longer supported](#bannericon---no-longer-supported)
    - [BodyText](#bodytext)
      - [`BodyText.inline`, `BodyText.italic` and `BodyText.bold` - No longer supported](#bodytextinline-bodytextitalic-and-bodytextbold---no-longer-supported)
        - [Summary](#summary-2)
        - [Next steps](#next-steps-2)
    - [Button](#button)
      - [`Button.appearance` - Invalid combinations](#buttonappearance---invalid-combinations)
        - [Summary](#summary-3)
        - [Next steps](#next-steps-3)
      - [`Button.full` and `Button.width` - No longer supported](#buttonfull-and-buttonwidth---no-longer-supported)
        - [Summary](#summary-4)
        - [Next steps](#next-steps-4)
      - [`Button.icon` - Verify SVG component](#buttonicon---verify-svg-component)
        - [Summary](#summary-5)
        - [Next steps](#next-steps-5)
      - [`Button.inactive` - No longer supported](#buttoninactive---no-longer-supported)
        - [Summary](#summary-6)
        - [Next steps](#next-steps-6)
      - [`Button.xsmall` and `Button.size="xsmall"` - No longer supported](#buttonxsmall-and-buttonsizexsmall---no-longer-supported)
        - [Summary](#summary-7)
        - [Next steps](#next-steps-7)
    - [Button Group](#button-group)
      - [`ButtonGroup.attached` - Not supported in `Flex`](#buttongroupattached---not-supported-in-flex)
        - [Summary](#summary-8)
        - [Next steps](#next-steps-8)
      - [`ButtonGroup.equalWidth` - Not supported in `Flex`](#buttongroupequalwidth---not-supported-in-flex)
        - [Summary](#summary-9)
        - [Next steps](#next-steps-9)
      - [`ButtonGroup.fullWidth` - Not supported in `Flex`](#buttongroupfullwidth---not-supported-in-flex)
        - [Summary](#summary-10)
        - [Some options:](#some-options)
        - [Next steps](#next-steps-10)
    - [Eyebrow](#eyebrow)
      - [`Eyebrow.inline`, `Eyebrow.italic` and `Eyebrow.bold` - No longer supported](#eyebrowinline-eyebrowitalic-and-eyebrowbold---no-longer-supported)
        - [Summary](#summary-11)
        - [Next steps](#next-steps-11)
    - [Headline](#headline)
      - [`Headline.inline`, `Headline.italic`, `Headline.subdued` and `Headline.bold` - No longer supported](#headlineinline-headlineitalic-headlinesubdued-and-headlinebold---no-longer-supported)
        - [Summary](#summary-12)
        - [Next steps](#next-steps-12)
      - [`Headline.el` - Now required](#headlineel---now-required)
        - [Summary](#summary-13)
        - [Next steps](#next-steps-13)
    - [Link](#link)
      - [`Link` as a button (no `href`) - No longer supported](#link-as-a-button-no-href---no-longer-supported)
        - [Summary](#summary-14)
        - [Next steps](#next-steps-14)
      - [`Link.disabled` - No longer supported](#linkdisabled---no-longer-supported)
        - [Summary](#summary-15)
        - [Next steps](#next-steps-15)
      - [`Link.negative` - No longer supported](#linknegative---no-longer-supported)
        - [Summary](#summary-16)
        - [Next steps](#next-steps-16)
    - [Stack](#stack)
      - [`Stack.Item` - Converted to `div`](#stackitem---converted-to-div)
        - [Summary](#summary-17)
        - [Next steps](#next-steps-17)
      - [`Stack.vertical` - Requires manual conversion](#stackvertical---requires-manual-conversion)
        - [Summary](#summary-18)
        - [Next steps](#next-steps-18)
      - [`Stack.nowrap` - Removed](#stacknowrap---removed)
        - [Summary](#summary-19)
        - [Next steps](#next-steps-19)
      - [`Stack.alignment` - Requires manual conversion](#stackalignment---requires-manual-conversion)
        - [Summary](#summary-20)
        - [Next steps](#next-steps-20)
      - [`Stack.distribution` - Requires manual conversion](#stackdistribution---requires-manual-conversion)
        - [Summary](#summary-21)
        - [Next steps](#next-steps-21)
      - [`Stack.distribution` - Unsupported values](#stackdistribution---unsupported-values)
        - [Summary](#summary-22)
        - [Next steps](#next-steps-22)
      - [`Stack` spread props - Requires manual verification](#stack-spread-props---requires-manual-verification)
        - [Summary](#summary-23)
        - [Next steps](#next-steps-23)
        - [Example](#example)
    - [Tag](#tag)
      - [`Tag.subtle` - No longer supported](#tagsubtle---no-longer-supported)
        - [Summary](#summary-24)
        - [Next steps](#next-steps-24)
      - [`Tag.color` - No longer supported](#tagcolor---no-longer-supported)
        - [Summary](#summary-25)
        - [Next steps](#next-steps-25)

## Contributing

Contributions are encouraged! See the [Contributing docs](./CONTRIBUTING.md) for instructions.

## Using the codemods

To use this CLI tool to upgrade code from Anvil (`@servicetitan/design-system`) to Anvil2 (`@servicetitan/anvil2`), we recommend using `npx` to always use the latest version.

```
npx @servicetitan/anvil2-codemods@latest [path] [transforms] [options]
```

Using the `--help` option will give you the following description:

```
Arguments:
  path                    Files or directory to transform. Can be a glob like src/**.test.js. Can be relative path from current working directory or absolute path.
  transforms              One or many of the choices separated by comma (no space). Available choices are all,button. See
                          https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods/README.md#transforms for more information.

Options:
  -f, --force             Bypass Git safety checks and forcibly run codemods
  --dry                   Dry run (no changes are made to files)
  --print                 Print transformed files
  --jscodeshift='<ARGS>'  Space separated jscodeshift CLI options. For example, --jscodeshift='--silent --run-in-band'. See https://jscodeshift.com/run/cli/#options for more information.
  -h, --help              Display this help
```

> See the [JSCodeshift docs](https://jscodeshift.com/run/cli/#options) for more info no available options to pass to `--jscodeshift`.

### Transforms

These are all of the transforms currently available that can be passed as the second argument of the CLI:

- `all`
- `banner`
- `body-text`
- `button`
- `button-group`
- `eyebrow`
- `headline`
- `link`
- `stack`
- `tag`
- `tag-group`

If no transform is passed, a menu will appear to manually select transform(s) to run.

### Formatting after transforms

Due to the nature of how codemods are run, formatting using Prettier or similar tools is not done during the transform. You will likely need to reformat the page after running a codemod to match the project standards.

> This is not something we plan to incorporate into the codemods tool, since there are many different tools, plugins, and configuration options for code formatting and linting.

## Docs for missing transforms

There are some transforms that can't be automated with a codemod, usually because the Anvil version doesn't have an exact match in Anvil2. In such cases, a comment will be added with some details and a links to this page or to the Anvil2 documentation.

The rest of this page has instructions for individual cases that could not be auto-transformed.

### Known issues (no automated message)

#### Removed import from Anvil that is used as a TypeScript Generic Parameter

If there is an import from `@servicetitan/design-system` that is only used on the page as a TypeScript generic parameter for a function (see example below), the import will be removed. This is related to [a known issue in `jscodeshift`](https://github.com/facebook/jscodeshift/issues/389).

```tsx
import { AnvilSelectMultipleProps } from "@servicetitan/design-system";

// ...other stuff...

/* 
  if this is the only AnvilSelectMultipleProps usage, the 
  import will be removed above
*/
const example = functionWithGenericParam<AnvilSelectMultipleProps>();
```

The solution is to manually add back the import that was removed. We will update the codemods once the issue is resolved on `jscodeshift`.

#### Anvil (1) Text components might need to be ran multiple times

There is an issue that occurs when multiple Anvil (1) components are mapped to a single Anvil2 component, where only one component is transformed at a time.

For example, if both a `<BodyText />` and `<Headline />` component are used, only one will be transformed the first time you run the code, and the other will remain as-is. This should be resolved by running the transform again.

### Generic messages

#### Component name changed and alias removed

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Component name changed and alias removed.
 * To continue using the alias name, manually adjust the import
 * statement and update the name here.
 */
```

##### Summary

Some components in Anvil map to new components in Anvil2 if they have a certain combination of props. For example, this Anvil `Button`:

```tsx
<Button href="https://something.com">Open link</Button>
```

would change to a `ButtonLink` in Anvil2:

```tsx
<ButtonLink href="https://something.com">Open link</ButtonLink>
```

Since there are other combinations of `Button` that _do not_ result in a `ButtonLink`, there are some complexities involved with determining how an alias would work for a `Button` import that is used both as a regular Anvil2 `Button` and as a `ButtonLink` in the same page.

Because of this, we ask that certain aliases are manually adjusted after the codemod is done. Here's a full example, again using `ButtonLink`:

```tsx
// before codemod
import { Button as AnvilButton } from "@servicetitan/design-system";

export const Component = () => (
  <>
    <AnvilButton>Regular Button</AnvilButton>
    <AnvilButton href="#">Button Link</AnvilButton>
  </>
);

// after codemod
import { Button as AnvilButton, ButtonLink } from "@servicetitan/anvil2";

export const Component = () => (
  <>
    <AnvilButton>Regular Button</AnvilButton>
    {/* ... codemods comment ... */}
    <ButtonLink href="#">Button Link</ButtonLink>
  </>
);
```

##### Next steps

1. Either manually update the alias for the the new component, or don't use an alias

</details>

#### `Component.el` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Component.el is no longer supported and has been removed from this component.
 * No action is required, but please verify this is the expected behavior.
 */
```

> [See documentation](https://anvil.servicetitan.com/web/components)

##### Summary

In Anvil2, the `el` prop has been removed to promote consistency and better accessibility in our components.

##### Next steps

1. Verify the behavior and any custom styles of this component is still correct

</details>

---

### Banner

#### `Banner.icon` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * The icon prop is no longer supported, and has been removed from this component.
 * Icons will always be displayed on the left side of the Anvil2 Alert.
 * No action is required, but please verify this is the expected behavior.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#bannericon---no-longer-supported
 */
```

> [See Alert documentation](https://anvil.servicetitan.com/web/components/alert?tab=design-spec)

</details>

### BodyText

#### `BodyText.inline`, `BodyText.italic` and `BodyText.bold` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The inline, italic, and bold props are no longer supported, and have been removed from this component.
 * No action is required, but please verify this is the expected behavior.
 */
```

> [See Body Text documentation](https://anvil.servicetitan.com/web/components/text?tab=design-spec#body-text)

##### Summary

In Anvil2, the `inline`, `italic`, and `bold` props are no longer supported. Body text is now created using the `Text` component with the `variant="body"` prop.

##### Next steps

1. Verify that the new `Text` component with `variant="body"` doesn't break the UI.
2. Manually remove `className="d-i"`, `className="fs-italic"`, `className="fw-bold"` from the `Text` component.
3. Make adjustments if needed.

</details>

---

### Button

#### `Button.appearance` - Invalid combinations

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * This combination of fill and color props is not supported
 * in Anvil2. Manually update the component to use a valid
 * appearance value.
 */
```

> [See Button appearance documentation](https://anvil.servicetitan.com/web/components/button?tab=design-spec#appearances)

##### Summary

In Anvil, a combination of fill and color props could be used to create many variations of buttons. These props included:

- `color`
- `fill`
- `negative`
- `outline`
- `primary`
- `text`

In Anvil2, we've reduced the possible combinations and have a single `appearance` prop, which allows:

- `"primary"`
- `"secondary"`
- `"danger"`
- `"danger-secondary"`
- `"ghost"`

For any combination that doesn't easily translate from Anvil to Anvil2, manual intervention is required to set the new `appearance`. For example, a `blue`/`outline` button from Anvil could be either a `"primary"` or `"secondary"` button in Anvil2, depending on context.

##### Next steps

1. Verify the correct `appearance` with your designer
2. Remove any of the original Anvil props
3. Add the correct `appearance` prop

</details>

#### `Button.full` and `Button.width` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The Button.width and Button.full props are no longer supported.
 * Action required. Either:
 *  - Add styles to a CSS class passed to Button.className
 *  - Use the Button.flexGrow or Button.flexBasis prop if
 *    parent is a Flex component or has display="flex"
 */
```

> [See Button documentation](https://anvil.servicetitan.com/web/components/button?tab=implementation)

##### Summary

In Anvil2, the `Button.width` and `Button.full` props are no longer supported. Custom styles must be added using one of the methods mentioned in the comment.

##### Next steps

1. Use CSS or Flex/Grid properties to achieve the desired button width

</details>

#### `Button.icon` - Verify SVG component

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The Anvil2 Button.icon prop should be an SVG component.
 * Make sure to update the custom Button.icon component value.
 */
```

> [See Button documentation](https://anvil.servicetitan.com/web/components/button?tab=implementation)

##### Summary

In Anvil2, the component passed to the `Button.icon` prop must be of `Svg` type:

```tsx
type Svg = FC<SVGProps<SVGSVGElement>>;
```

`*.svg` files imported in projects that use `svgo` (default in ST MFEs and monolith) are converted to this type.

There may be no further action required, but if a TypeScript error crops up, the `icon` may need to be refactored to use the correct type, rather than the `React.ReactElement` type in Anvil.

##### Next steps

1. If a TypeScript error occurs, or the icon is not rendered, replace the current component with an SVG component.

</details>

#### `Button.inactive` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The Button.inactive prop is no longer supported, and has been changed to Button.disabled in this component.
 * No action is required, but please verify this is the expected behavior with your designer.
 */
```

> [See Button documentation](https://anvil.servicetitan.com/web/components/button?tab=implementation)

##### Summary

In Anvil2, the `inactive` prop has been removed to promote consistency and better accessibility in our components. It is automatically replaced with `disabled`, which similarly prevents interactions, but also updates the UI and adds accessibility properties related to disabled elements.

##### Next steps

1. Verify that the button should be disabled

</details>

#### `Button.xsmall` and `Button.size="xsmall"` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Button.size="xsmall" is no longer supported. This Button has been changed to small.
 * No action is required, but please verify this is the expected behavior with your designer.
 */
```

> [See Button size documentation](https://anvil.servicetitan.com/web/components/button?tab=design-spec#sizes)

##### Summary

In Anvil2, `xsmall` buttons are no longer supported, either through the `xsmall` or `size="xsmall"` props. The button is automatically converted to a `small` button, but this may require some manual style adjustments if it breaks the UI.

##### Next steps

1. Verify that the new button size doesn't break the UI.
2. Make adjustments if needed.

</details>

---

### Button Group

#### `ButtonGroup.attached` - Not supported in `Flex`

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * ButtonGroup.attached is no longer supported and has been removed from this component.
 * Action required.
 *  - Work with designer to decide if the design should update
 *  - If not, remove gap="2" and add custom styles to Button children
 *    to achieve desired UI.
 */
```

> [See Flex documentation](https://anvil.servicetitan.com/web/components/flex?tab=implementation)

##### Summary

Since the `ButtonGroup` no longer exists in Anvil2, and the `Flex` component does not have an `attached` prop, this behavior must be done custom. A designer should verify that this UI is still the expectation versus having a gap between the buttons.

##### Next steps

1. Work with designer to decide if the design should update
2. If not, remove gap="2" and add custom styles to Button children to achieve desired UI.

</details>

#### `ButtonGroup.equalWidth` - Not supported in `Flex`

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * The ButtonGroup.equalWidth prop is no longer supported,
 * and at least one child could not be identified as a Button.
 * Action required. Either:
 *  - Add flexGrow="1" to all children if Anvil2 Buttons
 *  - Use styles in a CSS class on all children with flex-grow: 1
 */
```

> [See Flex documentation](https://anvil.servicetitan.com/web/components/flex?tab=implementation)

##### Summary

Since the `ButtonGroup` no longer exists in Anvil2, and the `Flex` component does not have an `equalWidth` prop, this behavior must be done custom.

The codemod will automatically add `flexGrow="1"` to all `Button` components that are direct children of the new `Flex` component. For more complex cases, such as using a `map` function, the prop should be added manually.

This message will also appear if there are any JSX Element children that are not specifically named `Button`. If using an alias or passing through props to an Anvil2 `Button`, adding `flexGrow="1"` should work, otherwise you may need to add custom styles using a CSS class with `flex-grow: 1`.

> **Note:** You will also need to add custom styling for the `fullWidth` prop, which is used with `equalWidth`. More on that below.

##### Next steps

1. Add CSS styles via the `flexGrow="1"` prop on all children, or with custom CSS

</details>

#### `ButtonGroup.fullWidth` - Not supported in `Flex`

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * The ButtonGroup.fullWidth prop is no longer supported.
 * Action required. Either:
 *  - Add styles to a CSS class passed to Flex.className
 *  - Use the Flex.grow or Flex.basis prop if used within
 *    another Flex component or container with display="flex"
 */
```

> [See Flex documentation](https://anvil.servicetitan.com/web/components/flex?tab=implementation)

##### Summary

Since the `ButtonGroup` no longer exists in Anvil2, and the `Flex` component does not have a `fullWidth` prop, this behavior must be done custom. This can be done a few ways, and depends on the parent element of the new `Flex` component.

##### Some options:

- Add `width: 100%` to styles
- Use `grow="1"` on `Flex` if parent is also a flex container and has full-width
- Use grid props, such as `gridColumn` or `gridArea`, if the parent is a grid container

##### Next steps

1. Add CSS styles to create a full-width button group using a `Flex`

</details>

---

### Eyebrow

#### `Eyebrow.inline`, `Eyebrow.italic` and `Eyebrow.bold` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The inline, italic, and bold props are no longer supported, and have been removed from this component.
 * No action is required, but please verify this is the expected behavior.
 */
```

> [See Eyebrow documentation](https://anvil.servicetitan.com/web/components/text?tab=design-spec#eyebrow)

##### Summary

In Anvil2, the `inline`, `italic`, and `bold` props are no longer supported. Eyebrows are now created using the `Text` component with the `variant="eyebrow"` prop.

##### Next steps

1. Verify that the new `Text` component with `variant="eyebrow"` doesn't break the UI.
2. Manually remove `className="d-i"`, `className="fs-italic"`, `className="fw-bold"` from the `Text` component.
3. Make adjustments if needed.

</details>

---

### Headline

#### `Headline.inline`, `Headline.italic`, `Headline.subdued` and `Headline.bold` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The inline, italic, subdued, and bold props are no longer supported, and have been removed from this component.
 * No action is required, but please verify this is the expected behavior.
 */
```

> [See Headline documentation](https://anvil.servicetitan.com/web/components/text?tab=design-spec#headline)

##### Summary

In Anvil2, the `inline`, `italic`, `subdued`, and `bold` props are no longer supported. Headlines are now created using the `Text` component with the `variant="headline"` prop.

##### Next steps

1. Verify that the new `Text` component with `variant="headline"` doesn't break the UI.
2. Manually remove `className="d-i"`, `className="fs-italic"`, `className="fw-bold"` from the `Text` component.
3. Make adjustments if needed.

</details>

#### `Headline.el` - Now required

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The el prop is required and has been added to this component based on the previous size prop (${size} = ${el}).
 * Please verify this is the expected semantic element.
 */

// OR

/*
 * TODO (anvil2-codemods generated)
 * The el prop is required and has been added to this component (default "h3").
 * Please verify this is the expected semantic element.
 */

// OR

/*
 * TODO (anvil2-codemods generated)
 * The el prop is required and should be one of: h1, h2, h3, h4, h5, h6.
 * The el prop has been updated from to "h3" for this component.
 */
```

> [See Headline documentation](https://anvil.servicetitan.com/web/components/text?tab=design-spec#headline)

##### Summary

In Anvil2, the `el` prop is required on `Text` when `variant="headline"`. A valid `el` is important for semantics and accessibility. We apply an imperfect system to set this value for you:

- If your A1 `Headline` had an `el` prop, we use that if it is `h1`, `h2`, `h3`, `h4`, `h5`, or `h6`.
- If your A1 `Headline` had a `size` prop, we attempt to infer a correct value for `el` (`small` = `h4`, `medium`=`h3`, `large`=`h2`, `xlarge`=`h1`).
- If the values of `el` or `size` are invalid or unknown, we default to `h3`.

##### Next steps

1. Verify that the new `Text` component with `variant="headline"` has an appropriate heading level. Refer to MDN for [more info on heading levels](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements).
2. Make adjustments if needed.

</details>

---

### Link

#### `Link` as a button (no `href`) - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Link should not be used as a button for proper screen reader announcements.
 * Use a Button with appearance="ghost" instead.
 * Please verify this is the expected behavior with your designer.
 */
```

> [See Link documentation](https://anvil.servicetitan.com/web/components/link?tab=implementation)

##### Summary

In Anvil2, the `href` attribute should always be used with a `Link`. It should not be used as a link-styled button element. The next best option would be to use a `Button` with `appearance="ghost"`.

##### Next steps

1. Replace the `Link` with a `Button` if it is meant to behave like a button.
2. Or, add the `href` attribute.

</details>

#### `Link.disabled` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Link.disabled is no longer supported and has been removed
 * from this component. Please verify this is the expected
 * behavior with your designer.
 */
```

> [See Link variations documentation](https://anvil.servicetitan.com/web/components/link?tab=implementation#link-variations)

##### Summary

In Anvil2, links can no longer be disabled.

##### Next steps

1. Verify if any other changes should be made with your designer
2. Add custom styles using `className`, if necessary

</details>

#### `Link.negative` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Link.negative is no longer supported and has been removed
 * from this component. Please verify this is the expected
 * behavior with your designer.
 */
```

> [See Link variations documentation](https://anvil.servicetitan.com/web/components/link?tab=implementation#link-variations)

##### Summary

In Anvil2, links can no longer be negative in order to conform to accessibility best practices. Using only color to represent meaning is problematic for colorblind users, and red text generally has worse contrast ratios with certain background colors.

##### Next steps

1. Verify if any other changes should be made with your designer
2. Add custom styles using `className`, if necessary

</details>

---

### Stack

#### `Stack.Item` - Converted to `div`

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Stack.Item has been converted to a div with inline styles.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stackitem---converted-to-div
 */
```

##### Summary

The `Stack.Item` subcomponent has been replaced with a regular `div` element. The codemod will automatically convert Stack.Item-specific props to inline styles:

- `fill` → `style={{ flex: "1 1 auto" }}`
- `basis` → `style={{ flexBasis: ... }}`
- `grow` → `style={{ flexGrow: ... }}`
- `shrink` → `style={{ flexShrink: ... }}`
- `order` → `style={{ order: ... }}`
- `alignSelf` → kept as a prop

##### Next steps

1. Verify the converted styles work as expected
2. If there's an existing `style` prop, manually merge the generated styles

</details>

#### `Stack.vertical` - Requires manual conversion

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The vertical prop has been removed. Please manually update this to use
 * direction="column" if vertical is true, or direction="row" (default) if false.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stackvertical---requires-manual-conversion
 */
```

##### Summary

If the `vertical` prop uses a dynamic expression (not a boolean literal), the codemod cannot automatically convert it and will add a comment.

##### Next steps

1. Manually update the prop to use `direction="column"` or `direction="row"`
2. Remove the `vertical` prop

</details>

#### `Stack.nowrap` - Removed

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The nowrap prop has been removed. Flex uses the wrap prop instead.
 * If you need nowrap behavior, add wrap="nowrap" to the Flex component.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stacknowrap---removed
 */
```

##### Summary

The `nowrap` prop has been removed. If you need to prevent wrapping, use `wrap="nowrap"` on the Flex component instead.

##### Next steps

1. If nowrap behavior is needed, add `wrap="nowrap"` to the Flex component
2. Otherwise, no action is required

</details>

#### `Stack.alignment` - Requires manual conversion

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The alignment prop has been converted to alignItems. Please manually update
 * the value mapping: leading → flex-start, trailing → flex-end, center → center,
 * fill → stretch, baseline → baseline.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stackalignment---requires-manual-conversion
 */
```

##### Summary

If the `alignment` prop uses a dynamic expression, the codemod cannot automatically convert it.

##### Next steps

1. Manually convert the value using the mapping above
2. Rename the prop to `alignItems`

</details>

#### `Stack.distribution` - Requires manual conversion

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The distribution prop has been converted to justifyContent. Please manually update
 * the value mapping: leading → flex-start, trailing → flex-end, center → center,
 * equalSpacing → space-between. Note: fill and fillEvenly are not supported.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stackdistribution---requires-manual-conversion
 */
```

##### Summary

If the `distribution` prop uses a dynamic expression, the codemod cannot automatically convert it.

##### Next steps

1. Manually convert the value using the mapping above
2. Rename the prop to `justifyContent`
3. For `fill` and `fillEvenly` values, choose an appropriate alternative

</details>

#### `Stack.distribution` - Unsupported values

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The distribution="fill" value is not supported in Flex.
 * Please manually update to use an appropriate justifyContent value.
 * Available values: flex-start, flex-end, center, space-between, space-around, space-evenly.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stackdistribution---unsupported-values
 */
```

##### Summary

The `distribution` values `fill` and `fillEvenly` are not supported in the Flex component.

##### Next steps

1. Choose an appropriate `justifyContent` value for your use case
2. Update the component accordingly

</details>

#### `Stack` spread props - Requires manual verification

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * Unable to statically analyze spread props. Please verify all spread props
 * are valid for the Flex component.
 * https://github.com/servicetitan/hammer/tree/main/packages/anvil2-codemods#stack-spread-props
 */
```

##### Summary

When a Stack component uses spread props (e.g., `<Stack {...props}>`), the codemod cannot statically analyze what props are being spread. You'll need to manually verify that all spread props are valid for the Flex component.

##### Next steps

1. Review the spread props object and verify all props are compatible with Flex
2. Check for and convert any deprecated Stack props:
   - `vertical` → `direction`
   - `nowrap` → remove (use `wrap="nowrap"` if needed)
   - `alignment` → `alignItems`
   - `distribution` → `justifyContent`
   - `spacing` → `gap`

##### Example

**Before:**

```tsx
const stackProps = {
  vertical: true,
  spacing: 2,
  alignment: "center",
};

<Stack {...stackProps}>Content</Stack>;
```

**After codemod:**

```tsx
{
  /* Warning comment about spread props */
}
<Flex {...stackProps}>Content</Flex>;
```

**Manually fix to:**

```tsx
const flexProps = {
  direction: "column",
  gap: "4",
  alignItems: "center",
};

<Flex {...flexProps}>Content</Flex>;
```

</details>

---

### Tag

#### `Tag.subtle` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The subtle prop is no longer supported, and has been removed from this component.
 * No action is required, but please verify this is the expected behavior.
 */
```

> [See Chip documentation](https://anvil.servicetitan.com/web/components/chip?tab=design-spec)

##### Summary

In Anvil2, the `subtle` prop is no longer supported.

##### Next steps

1. Verify that the new `Chip` component doesn't break the UI.
2. Make adjustments if needed.

</details>

#### `Tag.color` - No longer supported

<details>
  <summary>Expand for details</summary>

```tsx
/*
 * TODO (anvil2-codemods generated)
 * The color prop is no longer supports the info, warning, critical, success, inactive, and inverse values, and has been removed from this component.
 * No action is required, but please verify this is the expected behavior.
 */
```

> [See Chip documentation](https://anvil.servicetitan.com/web/components/chip?tab=design-spec)

##### Summary

In Anvil2, the `color` prop only supports color values such as HEX, RGB, HSL, and HSV.

##### Next steps

1. Verify that the new `Chip` component doesn't break the UI.
2. Make adjustments if needed.

</details>