diff --git a/.github/workflows/publish-storybook-pr-preview.yml b/.github/workflows/publish-storybook-pr-preview.yml
new file mode 100644
index 000000000..a91689b73
--- /dev/null
+++ b/.github/workflows/publish-storybook-pr-preview.yml
@@ -0,0 +1,36 @@
+name: Deploy Storybook PR preview
+
+on:
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - synchronize
+ - closed
+
+concurrency: preview-${{ github.ref }}
+
+jobs:
+ deploy-preview:
+ runs-on: ubuntu-latest
+ env:
+ GITHUB_TOKEN: ${{ secrets.MP_SEMANTIC_RELEASE_BOT }}
+ GIT_AUTHOR_NAME: mparticle-automation
+ GIT_AUTHOR_EMAIL: developers@mparticle.com
+ GIT_COMMITTER_NAME: mparticle-automation
+ GIT_COMMITTER_EMAIL: developers@mparticle.com
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Install and Build
+ if: github.event.action != 'closed' # You might want to skip the build if the PR has been closed
+ run: |
+ npm install
+ npm run build-storybook
+ touch ./storybook-static/.nojekyll
+
+ - name: Deploy preview
+ uses: rossjrw/pr-preview-action@v1
+ with:
+ source-dir: ./storybook-static/
diff --git a/.github/workflows/publish-storybook.yml b/.github/workflows/publish-storybook.yml
index f054f36b6..04c2a6367 100644
--- a/.github/workflows/publish-storybook.yml
+++ b/.github/workflows/publish-storybook.yml
@@ -1,20 +1,26 @@
name: Publish Storybook
-
on:
push:
branches:
- - 'main' # change to the branch you wish to deploy from
-
+ - main
permissions:
- contents: read
- pages: write
- id-token: write
-
+ contents: write
jobs:
- deploy:
+ build-and-deploy:
+ concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession.
runs-on: ubuntu-latest
steps:
- - id: build-publish
- uses: bitovi/github-actions-storybook-to-github-pages@v1.0.3
+ - name: Checkout ๐๏ธ
+ uses: actions/checkout@v4
+
+ - name: Install and Build ๐ง # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
+ run: |
+ npm ci
+ npm run build-storybook
+ touch ./storybook-static/.nojekyll
+
+ - name: Deploy ๐
+ uses: JamesIves/github-pages-deploy-action@v4
with:
- path: storybook-static
+ folder: storybook-static # The folder the action should deploy.
+ clean-exclude: pr-preview/
diff --git a/.storybook/main.ts b/.storybook/main.ts
index fa01a4780..3ae15aaef 100644
--- a/.storybook/main.ts
+++ b/.storybook/main.ts
@@ -2,6 +2,7 @@ import type { StorybookConfig } from '@storybook/react-vite'
import react from '@vitejs/plugin-react'
import { PluginOption, Plugin } from 'vite'
import { withoutVitePlugins } from '@storybook/builder-vite'
+import remarkGfm from 'remark-gfm'
type StorybookVitePlugins = { plugins: (PluginOption[] | Plugin)[] }
@@ -11,9 +12,24 @@ const config: StorybookConfig & StorybookVitePlugins = {
options: {},
},
- stories: ['../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)'],
-
- addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-interactions'],
+ stories: ['../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)', '../docs/**/*.stories.@(ts|tsx)', '../docs/**/*.mdx'],
+
+ addons: [
+ '@storybook/addon-links',
+ '@storybook/addon-essentials',
+ '@storybook/addon-interactions',
+ {
+ name: '@storybook/addon-docs',
+ options: {
+ mdxPluginOptions: {
+ mdxCompileOptions: {
+ // needed for rendering markdown tables in .mdx
+ remarkPlugins: [remarkGfm],
+ },
+ },
+ },
+ },
+ ],
docs: {
autodocs: true,
diff --git a/.storybook/preview.ts b/.storybook/preview.ts
deleted file mode 100644
index e02519090..000000000
--- a/.storybook/preview.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Preview } from '@storybook/react'
-
-const preview: Preview = {
- parameters: {
- layout: 'centered',
-
- controls: {
- matchers: {
- color: /(background|color)$/i,
- date: /Date$/i,
- },
- },
- },
-}
-
-export default preview
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
new file mode 100644
index 000000000..700f07a89
--- /dev/null
+++ b/.storybook/preview.tsx
@@ -0,0 +1,40 @@
+import type { Preview } from '@storybook/react'
+
+const preview: Preview = {
+ parameters: {
+ layout: 'centered',
+ options: {
+ storySort: {
+ order: [
+ 'About',
+ ['Introduction', 'Changelog', 'FAQ'],
+ 'Component Process',
+ [
+ 'Introduction',
+ 'Components',
+ ['Using components', 'Change process'],
+ 'Candidate Components',
+ ['Introducing new ones', 'Using existing ones', 'Promoting to a component'],
+ 'Design Templates',
+ ],
+ 'Foundations',
+ 'Components',
+ ['Colors', 'Typography', 'Icons', 'Errors', 'Loading'],
+ 'Candidate Components',
+ 'Design Templates',
+ 'Contributing',
+ ['Introduction', 'Commits', 'Testing in the platforms', 'Release Process', 'Maintainers'],
+ ],
+ },
+ },
+
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/i,
+ },
+ },
+ },
+}
+
+export default preview
diff --git a/docs/About/Changelog.mdx b/docs/About/Changelog.mdx
new file mode 100644
index 000000000..ea5f1bec3
--- /dev/null
+++ b/docs/About/Changelog.mdx
@@ -0,0 +1,7 @@
+import { Markdown } from "@storybook/blocks"
+
+import changelog from '../../CHANGELOG.md?raw'
+
+# CHANGELOG
+
+{changelog}
\ No newline at end of file
diff --git a/docs/About/FAQ.mdx b/docs/About/FAQ.mdx
new file mode 100644
index 000000000..e1e56fa86
--- /dev/null
+++ b/docs/About/FAQ.mdx
@@ -0,0 +1,6 @@
+# FAQ
+
+### What should I do if I can't implement my design specs using Antd atoms?
+
+Please ask questions about it in the #aquarium channel. Ideally have a branch with your work in progress and some Storybook
+stories so that we can see what you're trying to do.
\ No newline at end of file
diff --git a/docs/About/Introduction.mdx b/docs/About/Introduction.mdx
new file mode 100644
index 000000000..81502ac7d
--- /dev/null
+++ b/docs/About/Introduction.mdx
@@ -0,0 +1,20 @@
+# Introduction
+
+This is where all component related documentation will live at mParticle. This is mainly a work in progress at this point
+and we are actively working on it.
+
+## How to read this
+
+TBD
+
+## Glossary
+
+| Term | Meaning |
+| -------- | ------- |
+| Component Candidate | TBD |
+| Template | TBD |
+| Eames | TBD |
+| Aquarium | TBD |
+| Antd | TBD |
+
+---
\ No newline at end of file
diff --git a/docs/Candidate Components/Directory/Date Range Filter/DateRangeString.tsx b/docs/Candidate Components/Directory/Date Range Filter/DateRangeString.tsx
new file mode 100644
index 000000000..858278af5
--- /dev/null
+++ b/docs/Candidate Components/Directory/Date Range Filter/DateRangeString.tsx
@@ -0,0 +1,19 @@
+const DEFAULTS = {
+ month: 'short',
+ day: 'numeric',
+ year: 'numeric',
+} as const
+
+export interface IDateRangeStringProps {
+ start: Date
+ end: Date
+ formatOptions?: Intl.DateTimeFormatOptions
+}
+
+export const DateRangeString = ({ start, end, formatOptions = DEFAULTS }: IDateRangeStringProps) => (
+ <>
+ {new Intl.DateTimeFormat('en-US', {
+ ...formatOptions,
+ }).formatRange(start, end)}
+ >
+)
diff --git a/docs/Candidate Components/Directory/Date Range Filter/Documentation.mdx b/docs/Candidate Components/Directory/Date Range Filter/Documentation.mdx
new file mode 100644
index 000000000..531d19323
--- /dev/null
+++ b/docs/Candidate Components/Directory/Date Range Filter/Documentation.mdx
@@ -0,0 +1,47 @@
+import { Meta, Story } from '@storybook/blocks';
+
+import * as SelectWithRangePickerStories from './SelectWithRangePicker.stories';
+
+
+
+# Date Range Filter
+
+**Overview**
+
+The Date Range Filter is used when a user needs to narrow down the dataset they are working with to a specific date
+and/or time window, allowing users to focus on data relevant to the selected timeframe.
+
+**Key Components**
+
+The Date Range Filter consists of two main components:
+
+- [Select Component](?path=/docs/components-data-entry-select--documentation)
+- [Range Picker](https://ant.design/components/date-picker#date-picker-demo-range-picker)
+
+**mParticle Usage**
+
+The Date Range Filter can be used in dashboards, reports, or any interfaces where users interact with time-based data.
+
+
+
+
+
+## Current usages
+
+**9/25/2024 - Observability Project in CDP**
+
+
+
diff --git a/docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker.stories.tsx b/docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker.stories.tsx
new file mode 100644
index 000000000..1945a1e6e
--- /dev/null
+++ b/docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker.stories.tsx
@@ -0,0 +1,46 @@
+import React from 'react'
+import type { Meta, StoryObj } from '@storybook/react'
+import { SelectWithRangePicker as Component } from './SelectWithRangePicker'
+import { fn } from '@storybook/test'
+import { useArgs } from '@storybook/preview-api'
+
+const meta: Meta = {
+ title: 'Candidate Components/Directory/Date Range Filter',
+ component: Component,
+}
+export default meta
+
+type Story = StoryObj
+
+export const DateRangeFilter: Story = {
+ args: {
+ value: 'last30days',
+ onSelect: fn(),
+ options: [
+ {
+ value: 'last24hours',
+ label: 'Last 24 hours',
+ },
+ {
+ value: 'last7days',
+ label: 'Last 7 days',
+ },
+ {
+ value: 'last30days',
+ label: 'Last 30 days',
+ },
+ ],
+ },
+ render: function Render(args) {
+ const [{ value }, updateArgs] = useArgs()
+ return (
+ {
+ updateArgs({ value })
+ }}
+ />
+ )
+ },
+}
diff --git a/docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker.tsx b/docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker.tsx
new file mode 100644
index 000000000..59f5a2873
--- /dev/null
+++ b/docs/Candidate Components/Directory/Date Range Filter/SelectWithRangePicker.tsx
@@ -0,0 +1,79 @@
+import React from 'react'
+import { Select } from 'antd'
+import { useMemo, useState } from 'react'
+import { DateRangeString, type IDateRangeStringProps } from './DateRangeString'
+import type { RangePickerProps } from 'antd/es/date-picker'
+import type { BaseOptionType, DefaultOptionType } from 'antd/es/select'
+import dayjs from 'dayjs'
+import { DatePicker, Divider, Flex, type ISelectProps, Typography } from 'src/components'
+
+export type SelectWithRangePickerValue = ValueType | [string, string] | null
+
+interface SelectWithRangePickerProps
+ extends Omit<
+ // @ts-expect-error only used in stories as an example
+ ISelectProps, OptionType>,
+ 'open' | 'value' | 'dropdownRender' | 'defaultValue' | 'mode'
+ > {
+ value: SelectWithRangePickerValue
+ rangePickerProps?: Omit
+ rangePickerLabel?: React.ReactNode
+ formatOptions?: IDateRangeStringProps['formatOptions']
+}
+
+const DEFAULT_PICKER_LABEL = Custom date range
+
+export const SelectWithRangePicker = <
+ ValueType = SelectWithRangePickerValue,
+ OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
+>({
+ value,
+ rangePickerProps = {},
+ rangePickerLabel = DEFAULT_PICKER_LABEL,
+ formatOptions,
+ ...rest
+}: SelectWithRangePickerProps) => {
+ const [open, setOpen] = useState(undefined)
+
+ return (
+