# @flytedan/flytebot-design-system

The flytedesk Design System's Media Planner UI kit, ported to a standalone,
framework-agnostic-consumer npm package: React 18 + TypeScript components,
tokens, and business-logic kits for flytedesk apps.

## Install

```bash
pnpm add @flytedan/flytebot-design-system
```

`react` and `react-dom` (^18.3.1) are peer dependencies.

## Usage

Import the vendored CSS once, near your app's entry point, then use components
directly:

```tsx
import "@flytedan/flytebot-design-system/styles/tokens.css";
import "@flytedan/flytebot-design-system/styles/foundations.css";
import "@flytedan/flytebot-design-system/styles/components.css";
// foundations.css also imports icons.css (the Phosphor icon font every
// component's `<i className="ph ph-*">` needs) — no separate link required.

import { Button, Card, DataTable } from "@flytedan/flytebot-design-system";

function Example() {
  return (
    <Card>
      <Button variant="primary">Save</Button>
    </Card>
  );
}
```

## What's in the package

**32 core components** across seven groups — actions (Button, IconButton,
SegmentedControl, Popover, Menu, MenuButton), forms (Input, NumberInput,
Textarea, Select, DatePicker, TimePicker, Checkbox, Radio, Switch, Slider,
RangeSlider, FileGrid, Dropzone, MarkdownEditor), surfaces (Card, CardRow,
Collapsible, Modal, Drawer), data (DataTable, FactList, Pagination, SortMenu, StatTile,
Meter, CsiBadge, CsiMeter, CsiHero, Markdown, CodeBlock, DiffBlock, StepList,
SegmentedMeter, QuotaRow, Clamp, RelativeTime), feedback (Badge, Tag, Avatar,
AvatarStack, Flag, Toast, Tooltip, EmptyState, KeyHint), loading (Skeleton,
SkeletonText, ReservedSkeleton, LoadingRegion, Spinner, ProgressBar), and navigation (Tabs,
SidebarNav, Topbar).

**Platform components** for identity/session UI — AccountMenu,
ApiSpecBrowser, Gate/FeatureGate/PermissionDenied/PermissionHint,
ProfilePage, ComingSoon, RoadmapTimeline, ModeSwitch/TestModeBar.

**Planner components** for media-planning UIs — SaturationDistribution,
MixGap, ChannelContribution, SurroundSound, BudgetReallocator, ChannelMeta.

**Chat components** — AgentChatPanel, ChatComposer, ChatSessionBar,
ChatTranscript, ChatTurn, chatEngine.

**Business-logic kits** (framework-light, no UI) — SessionKit (roles,
permissions, feature flags), QueryKit (paged/sorted/filtered list state via
`useServerTable`), RuntimeKit (feature-completeness/live-vs-test derivation),
FileKit, MockJobKit (`{ jobId } → poll` async job simulation), VersionKit
(append-only version history stores).

Every export has its own documented page — props transcribed from the real
TypeScript interfaces, a live interactive example, and a usage snippet — in
the docs site included in this repo (not yet published as a hosted site):

```bash
git clone git@github.com:Flytedesk/flytebot-design-system.git
cd flytebot-design-system
pnpm install
pnpm run docs
```

## Development

```bash
pnpm run build       # tsup — emits dist/{index.js,index.cjs,index.d.ts}
pnpm run typecheck   # tsc --noEmit
pnpm run lint        # eslint .
pnpm run test        # vitest run — needs no build
pnpm run test:dist   # tsup, then the checks of the built dist/ (scripts/vitest.dist.config.ts)
```

## Releasing

There is no publish CI. Releases are manual and run only from a dedicated
deploy clone — never hand-published from a working checkout, which could ship
whatever a builder happens to be mid-edit on.

One-time setup, once per machine:

```bash
git clone git@github.com:Flytedesk/flytebot-design-system.git C:/Users/newms/deploy/flytebot-design-system
cd C:/Users/newms/deploy/flytebot-design-system
touch .deploy-clone-marker   # git-ignored; scripts/release.sh refuses to run without it
```

Then, for every release:

```bash
cd C:/Users/newms/deploy/flytebot-design-system
bash scripts/release.sh <new-version> "<summary>"
```

`scripts/release.sh`:

- refuses to run anywhere except a directory carrying `.deploy-clone-marker`;
- refuses a dirty tree, and takes a `.release.lock` so two runs can't overlap;
- fetches `origin` and checks out `origin/main`'s exact tip — never unmerged
  work;
- re-executes the `scripts/release.sh` it just checked out, handing over the
  lock, so every later step (gates, bump, publish) is the released commit's
  own script, never the one that was on disk before the checkout (bash reads a
  script from the file it opened). The second pass is marked by
  `RELEASE_REEXEC_SHA`, which carries the checked-out commit: it asserts `HEAD`
  is that commit and skips the fetch and checkout;
- installs with `pnpm install --frozen-lockfile`;
- runs the gates: `tsup`, then straight away the checks of that build
  (`vitest run --config scripts/vitest.dist.config.ts`), then `vitest run`,
  `tsc --noEmit`, `tsc --noEmit -p tsconfig.docs.json`, the docs `vite build`,
  and `lint` if the repo has that script;
- refuses `<new-version>` unless it is greater than both the working
  checkout's `package.json` version and npm's currently published `latest`;
- bumps `package.json`, commits `chore(release): <new-version> — <summary>`,
  and pushes (failing on a non-fast-forward);
- `npm publish`es (account `flytedan`, via the existing `~/.npmrc`), then
  pushes tag `v<new-version>`;
- prints `RESULT: sha=<sha> version=<new-version> status=published` on
  success.

`scripts/release.test.ts` covers its guards (wrong directory, dirty tree,
held lock, missing/malformed version argument) and the re-execution (a fake
origin whose `release.sh` changed runs the new body; the second pass's `HEAD`
and lock checks) against throwaway git repos — no network, no real publish.

## License

UNLICENSED — internal flytedesk use only.
