Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
- uses: actions/setup-node@v4
with:
node-version: 20.x
node-version: 24.x
- run: yarn install --frozen-lockfile
- run: yarn run lint:prettier
- run: yarn run lint
Expand Down
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.13.0
3 changes: 3 additions & 0 deletions .storybook/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const defaultParameter = {
layout: 'fullscreen' as const,
};
42 changes: 0 additions & 42 deletions .storybook/example.stories.js

This file was deleted.

22 changes: 0 additions & 22 deletions .storybook/main.js

This file was deleted.

49 changes: 49 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type {StorybookConfig} from '@storybook/react-webpack5';
import type {Configuration} from 'webpack';
import {fileURLToPath} from 'url';
import {dirname, resolve} from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const config: StorybookConfig = {
stories: ['../examples/**/*.stories.@(tsx|ts|jsx|js)'],
framework: {
name: '@storybook/react-webpack5',
options: {fastRefresh: true, builder: {lazyCompilation: true}},
},
addons: [],
webpackFinal: async (config: Configuration) => {
// Add babel-loader rule for JSX/TS files in .storybook, examples, and src directories
// Use unshift to add this rule before Storybook's internal rules
config.module?.rules?.unshift({
test: /\.(jsx?|tsx?)$/,
include: [
resolve(__dirname, '../src'),
resolve(__dirname, '../.storybook'),
resolve(__dirname, '../examples'),
],
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-react', {runtime: 'automatic'}],
'@babel/preset-env',
'@babel/preset-typescript',
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
regenerator: true,
},
],
],
},
},
});
return config;
},
};

export default config;
2 changes: 1 addition & 1 deletion examples/.eslintrc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
extends: '../.eslintrc.yml'
extends: ["../.eslintrc.yml", "plugin:react/jsx-runtime"]
rules:
import/no-extraneous-dependencies: 0
16 changes: 16 additions & 0 deletions examples/class-components/0-Card-Minimal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type {Meta, StoryObj} from '@storybook/react';

import {defaultParameter} from '../../.storybook/constants';
import CardMinimal from './0-Card-Minimal';

const meta: Meta<typeof CardMinimal> = {
title: 'react-stripe-js/Class Components/Card Minimal',
component: CardMinimal,
parameters: defaultParameter,
};

export default meta;

type Story = StoryObj<typeof CardMinimal>;

export const Default: Story = {};
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
// This example shows you how to set up React Stripe.js and use Elements.
// Learn how to accept a payment using the official Stripe docs.
// https://stripe.com/docs/payments/accept-a-payment#web

import React from 'react';
import {loadStripe} from '@stripe/stripe-js';
import type {FormEventHandler} from 'react';
import {Component} from 'react';
import {loadStripe, Stripe, StripeElements} from '@stripe/stripe-js';
import {CardElement, Elements, ElementsConsumer} from '../../src';
import '../styles/common.css';

class CheckoutForm extends React.Component {
handleSubmit = async (event) => {
interface CheckoutFormProps {
stripe: Stripe | null;
elements: StripeElements | null;
}

class CheckoutForm extends Component<CheckoutFormProps> {
handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
// Block native form submission.
event.preventDefault();

Expand Down Expand Up @@ -79,7 +84,7 @@ const InjectedCheckoutForm = () => {
);
};

// Make sure to call `loadStripe` outside of a components render to avoid
// Make sure to call `loadStripe` outside of a component's render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh');

Expand Down
16 changes: 16 additions & 0 deletions examples/class-components/1-Card-Detailed.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type {Meta, StoryObj} from '@storybook/react';

import {defaultParameter} from '../../.storybook/constants';
import CardDetailed from './1-Card-Detailed';

const meta: Meta<typeof CardDetailed> = {
title: 'react-stripe-js/Class Components/Card Detailed',
component: CardDetailed,
parameters: defaultParameter,
};

export default meta;

type Story = StoryObj<typeof CardDetailed>;

export const Default: Story = {};
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,23 @@
// Learn how to accept a payment using the official Stripe docs.
// https://stripe.com/docs/payments/accept-a-payment#web

import React from 'react';
import {loadStripe} from '@stripe/stripe-js';
import type {ChangeEvent, FormEventHandler, ReactNode} from 'react';
import {Component} from 'react';
import {
loadStripe,
Stripe,
StripeElements,
PaymentMethod,
StripeError,
StripeCardElementChangeEvent,
} from '@stripe/stripe-js';
import {CardElement, Elements, ElementsConsumer} from '../../src';

import '../styles/common.css';
import '../styles/2-Card-Detailed.css';

const CARD_OPTIONS = {
iconStyle: 'solid',
iconStyle: 'solid' as const,
style: {
base: {
iconColor: '#c4f0ff',
Expand All @@ -33,12 +41,27 @@ const CARD_OPTIONS = {
},
};

const CardField = ({onChange}) => (
interface CardFieldProps {
onChange: (event: StripeCardElementChangeEvent) => void;
}

const CardField = ({onChange}: CardFieldProps) => (
<div className="FormRow">
<CardElement options={CARD_OPTIONS} onChange={onChange} />
</div>
);

interface FieldProps {
label: string;
id: string;
type: string;
placeholder: string;
required: boolean;
autoComplete: string;
value: string;
onChange: (event: ChangeEvent<HTMLInputElement>) => void;
}

const Field = ({
label,
id,
Expand All @@ -48,7 +71,7 @@ const Field = ({
autoComplete,
value,
onChange,
}) => (
}: FieldProps) => (
<div className="FormRow">
<label htmlFor={id} className="FormRowLabel">
{label}
Expand All @@ -66,7 +89,19 @@ const Field = ({
</div>
);

const SubmitButton = ({processing, error, children, disabled}) => (
interface SubmitButtonProps {
processing: boolean;
error: StripeError | null | undefined;
children: ReactNode;
disabled: boolean;
}

const SubmitButton = ({
processing,
error,
children,
disabled,
}: SubmitButtonProps) => (
<button
className={`SubmitButton ${error ? 'SubmitButton--error' : ''}`}
type="submit"
Expand All @@ -76,7 +111,11 @@ const SubmitButton = ({processing, error, children, disabled}) => (
</button>
);

const ErrorMessage = ({children}) => (
interface ErrorMessageProps {
children: ReactNode;
}

const ErrorMessage = ({children}: ErrorMessageProps) => (
<div className="ErrorMessage" role="alert">
<svg width="16" height="16" viewBox="0 0 17 17">
<path
Expand All @@ -92,7 +131,11 @@ const ErrorMessage = ({children}) => (
</div>
);

const ResetButton = ({onClick}) => (
interface ResetButtonProps {
onClick: () => void;
}

const ResetButton = ({onClick}: ResetButtonProps) => (
<button type="button" className="ResetButton" onClick={onClick}>
<svg width="32px" height="32px" viewBox="0 0 32 32">
<path
Expand All @@ -103,7 +146,22 @@ const ResetButton = ({onClick}) => (
</button>
);

const DEFAULT_STATE = {
interface CheckoutFormProps {
stripe: Stripe | null;
elements: StripeElements | null;
}

interface CheckoutFormState {
error: StripeError | null | undefined;
cardComplete: boolean;
processing: boolean;
paymentMethod: PaymentMethod | null;
email: string;
phone: string;
name: string;
}

const DEFAULT_STATE: CheckoutFormState = {
error: null,
cardComplete: false,
processing: false,
Expand All @@ -113,13 +171,13 @@ const DEFAULT_STATE = {
name: '',
};

class CheckoutForm extends React.Component {
constructor(props) {
class CheckoutForm extends Component<CheckoutFormProps, CheckoutFormState> {
constructor(props: CheckoutFormProps) {
super(props);
this.state = DEFAULT_STATE;
}

handleSubmit = async (event) => {
handleSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
event.preventDefault();

const {stripe, elements} = this.props;
Expand Down
16 changes: 16 additions & 0 deletions examples/class-components/2-Split-Card.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type {Meta, StoryObj} from '@storybook/react';

import {defaultParameter} from '../../.storybook/constants';
import SplitCard from './2-Split-Card';

const meta: Meta<typeof SplitCard> = {
title: 'react-stripe-js/Class Components/Split Card',
component: SplitCard,
parameters: defaultParameter,
};

export default meta;

type Story = StoryObj<typeof SplitCard>;

export const Default: Story = {};
Loading
Loading