freemium-survey-components 2.0.484 → 2.0.486
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adrs/.gitkeep +0 -0
- package/catalog-info.yaml +35 -0
- package/docs/adrs/index.md +21 -0
- package/docs/architecture/code-structure.md +118 -0
- package/docs/architecture/deep-dive.md +401 -0
- package/docs/getting-started.md +110 -0
- package/docs/index.md +57 -0
- package/docs/operations/alerts-configuration.md +19 -0
- package/docs/operations/how-to-debug.md +73 -0
- package/docs/operations/monitoring.md +26 -0
- package/docs/operations/recent-issues.md +22 -0
- package/docs/operations/sop.md +44 -0
- package/docs/operations/support.md +39 -0
- package/lib/bundle.css +1 -1
- package/lib/index.cjs.js +1 -1
- package/lib/index.esm.js +1 -1
- package/mkdocs.yml +38 -0
- package/package.json +1 -1
package/adrs/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Prism (Backstage) software catalog descriptor.
|
|
2
|
+
# Registers this repo as the shared survey-rendering component library of the
|
|
3
|
+
# SurveyServ system. The `platforms/surveyserv` System entity itself is
|
|
4
|
+
# declared in the freshdesk/surveyserv repo (see PR #5448) — not redeclared
|
|
5
|
+
# here to avoid a duplicate-entity conflict in the catalog.
|
|
6
|
+
# Schema: `get_catalog_schema` in the Prism MCP server is the source of truth.
|
|
7
|
+
apiVersion: backstage.io/v1alpha1
|
|
8
|
+
kind: Component
|
|
9
|
+
metadata:
|
|
10
|
+
name: freemium-survey-components
|
|
11
|
+
namespace: platforms
|
|
12
|
+
title: Freemium Survey Components
|
|
13
|
+
description: >-
|
|
14
|
+
Shared React UI component library that renders the SurveyServ survey
|
|
15
|
+
collection form from a survey definition object. Published as an npm
|
|
16
|
+
package and consumed by SurveyServ frontends (admin, public widget,
|
|
17
|
+
public page).
|
|
18
|
+
annotations:
|
|
19
|
+
github.com/project-slug: freshdesk/freemium-survey-components
|
|
20
|
+
backstage.io/techdocs-ref: dir:.
|
|
21
|
+
tags:
|
|
22
|
+
- survey
|
|
23
|
+
- react
|
|
24
|
+
- library
|
|
25
|
+
- typescript
|
|
26
|
+
- ui-components
|
|
27
|
+
labels:
|
|
28
|
+
exposure: internal
|
|
29
|
+
language: TypeScript
|
|
30
|
+
orgVersion: v1alpha1
|
|
31
|
+
spec:
|
|
32
|
+
type: library
|
|
33
|
+
lifecycle: production
|
|
34
|
+
owner: platforms/plat-maise-surveyserv
|
|
35
|
+
system: platforms/surveyserv
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Architecture Decision Records
|
|
2
|
+
|
|
3
|
+
No ADRs are recorded for this repo today — there is no `adrs/`-sourced decision record, and no
|
|
4
|
+
dedicated architecture-decision page was found in Confluence space `SP` beyond general
|
|
5
|
+
architecture/roadmap docs (e.g. "Frontend Roadmap — Surveyserv (Backlog 2026)",
|
|
6
|
+
"freemium-survey-components — Engineering Improvement Brief") which describe planned work rather
|
|
7
|
+
than ratified decisions.
|
|
8
|
+
|
|
9
|
+
Notable architectural choices that exist in code but are not backed by a written ADR (call these
|
|
10
|
+
out as "decision, not yet documented as an ADR" if you're relying on them):
|
|
11
|
+
|
|
12
|
+
- Two branching mechanisms coexist (`dependent_blocks` and `display_logic` — see
|
|
13
|
+
[Deep Dive → Idiomatic vernacular](../architecture/deep-dive.md#4-idiomatic-vernacular)) rather
|
|
14
|
+
than one being fully migrated/removed.
|
|
15
|
+
- The library maintains three parallel layout implementations (`card`, `standard`, `widget`) with
|
|
16
|
+
duplicated `SurveyEndCard`/`PageNavigator`/`QuestionFooter` components per layout rather than a
|
|
17
|
+
shared abstraction (see [Deep Dive → Architecture & control flow](../architecture/deep-dive.md#1-architecture--control-flow)).
|
|
18
|
+
- Peer-dependency-only React (no bundling) via Rollup's `external` config (`rollup.config.ts`).
|
|
19
|
+
|
|
20
|
+
When a real ADR is written for this repo, add source files under `adrs/` at the repo root and
|
|
21
|
+
list/link them from this page.
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Code Structure
|
|
2
|
+
|
|
3
|
+
This is the "where do I find X" map of `src/`, grouped by responsibility. Every file is real —
|
|
4
|
+
paths are exact as of this writing (see [Deep Dive → Staleness triggers](deep-dive.md#8-staleness-triggers)
|
|
5
|
+
for what invalidates this map).
|
|
6
|
+
|
|
7
|
+
## Entry points
|
|
8
|
+
|
|
9
|
+
| File | Description |
|
|
10
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
11
|
+
| `src/index.ts` | The npm package entry point. Re-exports `src/components`, `src/survey`, `src/survey/meta-channel-preview`, `src/types`, and a few constants (`ALL_FONTS`, `DEFAULT_FONT`, `FONT_SIZE_OPTIONS`). Everything exported transitively from here is the library's public surface. |
|
|
12
|
+
| `src/index.d.ts` | Hand-written extra ambient type re-exports (`components/text-input/types`, `components/pickers/types`) that aren't otherwise picked up by the Rollup TS declaration build. |
|
|
13
|
+
|
|
14
|
+
## Survey rendering shell — `src/survey/`
|
|
15
|
+
|
|
16
|
+
The layout/orchestration layer: turns a survey + answers into a navigable flow. Each layout
|
|
17
|
+
(`card`, `standard`, `widget`) has its own React component plus a shared hook from `src/survey/utils/`.
|
|
18
|
+
|
|
19
|
+
| File | Description |
|
|
20
|
+
| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
21
|
+
| `src/survey/index.tsx` | Top-level exported components: `Survey` (dispatches to `CardSurvey`/`StandardSurvey` based on `surveyStyle`), `WebInAppSurvey` (widget entry, shows a loader until `survey.id` exists), `QuestionPreview` (single-question, stateless preview used by the survey builder). |
|
|
22
|
+
| `src/survey/question.tsx` | `Question` — the single dispatcher that maps `question.type_info.question_type` to the concrete answer widget from `src/components/*`. This is the file to touch when adding a new question type. |
|
|
23
|
+
| `src/survey/card/index.tsx` | `CardSurvey` + `SurveyEndCard` — one-question-per-screen layout with animated transitions (used standalone and as the base for the widget). |
|
|
24
|
+
| `src/survey/standard/index.tsx` | `StandardSurvey` + `SurveyEndCard` — all-questions-on-one-page (classic form) layout, with paging support. |
|
|
25
|
+
| `src/survey/widget/index.tsx` | `Widget` — the floating/embedded chat-style widget shell (header, minimize/maximize, backdrop, unsubscribe footer) that wraps the widget-specific `Survey`. |
|
|
26
|
+
| `src/survey/widget/survey.tsx` | Widget-flavored `Survey` + `SurveyEndCard` (built on `useCardSurvey`) — adds widget-only concerns: dynamic height animation, progress bar, minimized-header text. |
|
|
27
|
+
| `src/survey/Links/index.tsx` | Renders the thank-you-page review/social/custom-button links block (`show_review_links`, `show_social_links`, `show_custom_button`). |
|
|
28
|
+
| `src/survey/end-card/*.tsx` | Thank-you visual variants: `CardThankYou`, `StandardThankYou`, `WidgetThankYou` (selected by `src/utils.tsx#thankYouComponent`). |
|
|
29
|
+
| `src/survey/survey.scss`, `src/survey/card/index.scss`, `src/survey/standard/index.scss`, `src/survey/widget/index.scss` | Layout-specific styles; consumed via Rollup's `postcss` plugin into `lib/bundle.css`. |
|
|
30
|
+
| `src/survey/*.stories.tsx`, `src/survey/SurveyStory.tsx`, `src/survey/WebInAppSurveyStory` equivalents | Storybook stories/fixtures for the top-level layouts. |
|
|
31
|
+
|
|
32
|
+
### Survey state & branching logic — `src/survey/utils/`
|
|
33
|
+
|
|
34
|
+
| File | Description |
|
|
35
|
+
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
36
|
+
| `src/survey/utils/use-survey.ts` | `useSurvey(survey, answers)` — normalizes a raw `SurveyType` into an `AugmentedSurveyType` (injects `question_names` into every block, deep-clones, filters out soft-deleted questions and their orphaned answers). Runs once per `survey.updated_at` change. Used by every layout entry point. |
|
|
37
|
+
| `src/survey/utils/use-card-survey.ts` | `useCardSurvey(props)` — all state/behavior for the card & widget layouts: rendered-block stack, pivot question/answer, per-statement matrix index, navigation, validation, submit. |
|
|
38
|
+
| `src/survey/utils/use-standard-survey.ts` | `useStandardSurvey(props)` — the standard-layout equivalent; additionally handles pages, "sets" (branch-separate-page groups), and pre-rendering multiple blocks at once (all questions visible, not just the active one). |
|
|
39
|
+
| `src/survey/utils/logics.ts` | ~2,800-line pure-function core: display logic evaluation (`evaluateConditions`, `getIsDisplay`), branching/skip navigation (`getNextLogicalBlock`, `fetchNextBlockIndex`, `getNextBlockIndex`), pivot-question resolution (`getPivotQuestion`, `getQuestionForBlock`), button enable/disable rules (`canDisplayButton`, `canDisableButton`), and field validators (`dateValidator`, `formValidator`, `textboxValidator`, `contactformValidator`, `fileUploadQnValidator`). See [Deep Dive → Architecture & control flow](deep-dive.md#1-architecture--control-flow). |
|
|
40
|
+
| `src/survey/utils/index.ts` | Barrel: re-exports `use-survey`, `use-card-survey`, and `logics` (note: `use-standard-survey` is **not** re-exported here — it's imported directly by `src/survey/standard/index.tsx`). |
|
|
41
|
+
|
|
42
|
+
### Chat-channel previews — `src/survey/meta-channel-preview/`
|
|
43
|
+
|
|
44
|
+
Renders the survey as it would appear inside WhatsApp / Instagram / Facebook Messenger / a generic
|
|
45
|
+
web-chat preview, for the collector-builder UI. Exported via `src/survey/meta-channel-preview` →
|
|
46
|
+
re-exported from `src/index.ts`.
|
|
47
|
+
|
|
48
|
+
| File | Description |
|
|
49
|
+
| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `src/survey/meta-channel-preview/index.tsx` | `ChannelPreview` (dispatches to chat/facebook/whatsapp/instagram renderers) and `ChannelLinkPreview` (renders just the outbound message/link-preview card for a channel). |
|
|
51
|
+
| `src/survey/meta-channel-preview/question.tsx` | Channel-specific question rendering (large file, ~1,300 lines — presentation + branching combined). |
|
|
52
|
+
| `src/survey/meta-channel-preview/answer.tsx` | Renders a previously-given answer bubble in the chat transcript; one of only two files in `src` that runs `DOMPurify.sanitize` before `dangerouslySetInnerHTML`. |
|
|
53
|
+
| `src/survey/meta-channel-preview/facebook/index.tsx`, `web-chat.tsx`, `preview-channel.tsx`, `meta-components.tsx`, `utils.tsx`, `RatingTypeIcon.tsx` | Per-channel chrome (Messenger frame, WhatsApp/Instagram frame, shared header/bubble components, rating icon mapping). |
|
|
54
|
+
| `*.scss`, `*.svg` | Channel-specific chat chrome styling and static art (`thankyou.svg`, `whatsapp-chat-bg.svg`). |
|
|
55
|
+
|
|
56
|
+
## Question-type & shared UI components — `src/components/`
|
|
57
|
+
|
|
58
|
+
Each subfolder is one question-type widget or shared primitive. `src/components/index.tsx` is the
|
|
59
|
+
barrel that decides what's re-exported to `src/index.ts` (and therefore public).
|
|
60
|
+
|
|
61
|
+
| File/folder | Description |
|
|
62
|
+
| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
63
|
+
| `src/components/index.tsx` | Barrel — re-exports `binary`, `Button`, `Checkbox`, `Dropdown`, `footer`, `Loader`, `PhoneNumberInput`, `DatePicker`, `DateTimePicker`, `progressbar`, `RadioGroup`, `range`, `rank-order`, `slider`, `survey-progress`, `text-input`. Anything **not** listed here (e.g. `matrix`, `matrix-widget`, `form-field`, `contact-form`, `file-qn`, `consent`, `number`, `textbox`, `questionComment`, `page-container`, `prompt`, `link-preview`, `icons`) is imported directly by path from `src/survey/question.tsx` and is **not** part of the npm package's public surface. |
|
|
64
|
+
| `src/components/binary/index.tsx` | `Binary` — Yes/No / thumbs-style boolean question (also used for `RESOLUTION` type). |
|
|
65
|
+
| `src/components/matrix/index.tsx`, `matrix-widget/index.tsx` | `Matrix` (standard/card layout) and `MatrixWidget` (mobile/widget layout, one statement at a time) for `MATRIX_RATING_SCALE`. |
|
|
66
|
+
| `src/components/range/index.tsx`, `range/utils.tsx` | `Range` — NPS/CSAT/CES point-scale question (emoji, star, number, text variants); exported directly from README's documented public API. |
|
|
67
|
+
| `src/components/rank-order/index.tsx` | `RankOrder` — drag-to-reorder question, built on `@dnd-kit`. |
|
|
68
|
+
| `src/components/slider/index.tsx` | `Slider` — numeric slider question, built on `@radix-ui/react-slider`. |
|
|
69
|
+
| `src/components/checkbox/*`, `radio-button/*`, `dropdown/index.tsx` | `CHECKBOX`/`MULTI_SELECT`, `RADIO`/`DROPDOWN` choice-question widgets, including "Others" free-text handling. |
|
|
70
|
+
| `src/components/text-input/*`, `textbox/index.tsx`, `number/index.tsx` | `TEXT`, `PARAGRAPH`, `NUMBER` question inputs. |
|
|
71
|
+
| `src/components/pickers/*` | `DatePicker`, `DateTimePicker` (`DATE`, `DATE_TIME` questions), built on `@blueprintjs/datetime2`; `constants.ts` holds `TIME_ZONE_SEPERATOR`. |
|
|
72
|
+
| `src/components/form-field/index.tsx`, `contact-form/index.tsx` | `FORM_FIELD` and `CONTACT_FORM` multi-field composite questions, each with its own per-field validators. |
|
|
73
|
+
| `src/components/file-qn/index.tsx` | `FILE` upload question, built on `filepond` + `@pqina/pintura` (image editor). |
|
|
74
|
+
| `src/components/consent/index.tsx` | `CONSENT` question (checkbox or button display format). |
|
|
75
|
+
| `src/components/questionComment/index.tsx` | The optional "add a comment" box attached to range/checkbox/radio/slider/boolean questions. |
|
|
76
|
+
| `src/components/matrix-widget`, `page-container`, `progressbar`, `survey-progress`, `prompt`, `link-preview`, `footer` | Layout/chrome primitives: paged-block accordion, progress bar/percentage, opt-in "prompt" screen shown before the survey starts, outbound link preview card, survey footer (branding/language dropdown). |
|
|
77
|
+
| `src/components/icons/index.tsx` | ~2,650-line SVG icon registry (`Icon` component + named icon components e.g. `WidgetClose`, `WidgetMaximize`, `WidgetMinimize`). |
|
|
78
|
+
| `src/components/button/index.tsx`, `Loader/index.tsx` | Shared `Button` (primary/secondary variants) and `Loader` spinner. |
|
|
79
|
+
| `*/style.scss` next to each component | Component-scoped styles, all rolled into the single `lib/bundle.css`. |
|
|
80
|
+
| `*.stories.tsx` next to relevant components | Component-level Storybook stories (`Button.stories.tsx`, `Checkbox.stories.tsx`, `Dropdown.stories.tsx`, `Radio.stories.tsx`, `RadioGroup.stories.tsx`, `DatePicker.stories.tsx`, `DateTimePicker.stories.tsx`, `Loader.stories.tsx`). |
|
|
81
|
+
|
|
82
|
+
## Types, constants, utils
|
|
83
|
+
|
|
84
|
+
| File | Description |
|
|
85
|
+
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
86
|
+
| `src/types.ts` | ~2,100-line single source of truth for every domain type: `SurveyType`, `SurveyQuestionType`, `CollectorType`, all the component prop types (`SurveyProps`, `WidgetProps`, `QuestionFooterProps`, …). See [Deep Dive → Idiomatic vernacular](deep-dive.md#4-idiomatic-vernacular) for the domain glossary. |
|
|
87
|
+
| `src/constants.ts` | Cross-cutting constants: `AUTO_COMMIT_FIELD_TYPES`, `SKIP_DISABLED_QUESTIONS`, animation durations (`CARD_ANIMATION_DURATION`, `TRANSITION_DURATION`), widget sizing tables (`WIDGET_MAX_HEIGHT`, `WIDGET_CONTAINER_WIDTH`), `EMOJI_PICK_HELPER`/`SCALE_TO_EMOJI` rating-to-icon maps, `REVIEW_PAGE_OPTIONS` (review-site logos for the thank-you page), and a full IANA `timeZones` lookup table. |
|
|
88
|
+
| `src/utils.tsx` | Cross-cutting pure helpers: `isNil`/`isEmpty`/`isRTL`, animation direction helpers (`initialAnimation`/`exitAnimation`), `resolvePlaceholders` (merges `{{...}}` placeholders + NPS/CSAT/CES rating tokens into question/thank-you text), `setCSSVariablesIfPresent` (writes theme colors as CSS custom properties on `document.documentElement`), `transformSurvey`, `getRangeToRender`, `appLogger`/`getFreshSurveyDebug` (debug logging gated by `localStorage`/`sessionStorage` flags), `setOrderForRenderedBlocks`. |
|
|
89
|
+
| `src/palette.ts` | Static brand color palette (hex values) used as CSS fallback defaults (e.g. `palette.S50` as a footer background fallback). |
|
|
90
|
+
| `src/global.d.ts`, `src/react-app-env.d.ts` | Ambient module declarations (SVG/SCSS imports, CRA env types). |
|
|
91
|
+
|
|
92
|
+
## Mocks & Storybook fixtures
|
|
93
|
+
|
|
94
|
+
| File | Description |
|
|
95
|
+
| -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
96
|
+
| `src/mocks/index.ts` | `MOCK_SURVEY` and related fixture exports — a full realistic `SurveyType` payload used across Storybook stories and manual dev. Not part of the npm package's runtime purpose; dev/test-only. |
|
|
97
|
+
| `src/mocks/gallery.ts`, `src/mocks/fchatgallery.ts` | Large fixture data (`gallery.ts` alone is ~30,600 lines) for gallery/file-question and chat-channel stories. |
|
|
98
|
+
| `src/stories/*.stories.tsx` + matching `*Story.tsx` | One pair per question type/scenario (Boolean, Consent, DateTime, DateTimeZone, File, FormFields, Gallery, LinkPreview, LongTextAnswer, Matrix{Single,Multiple}, Mcq{Single,Multiple}, Message, Number, QuestionPreview, Range, RankOrder, Slider, Textbox) plus `Channel.stories.tsx` / `ChannelLinkPreview.stories.tsx` for the chat previews. `*Story.tsx` holds the reusable render body; `*.stories.tsx` holds the Storybook `Meta`/`StoryObj` wiring. |
|
|
99
|
+
| `src/stories/utils.ts`, `src/stories/style.scss` | Shared story helpers/styles. |
|
|
100
|
+
| `src/survey/*.stories.tsx` (`Survey.stories.tsx`, `WebInAppSurvey.stories.tsx`, `QuestionPreview.stories.tsx`) | Top-level layout stories. |
|
|
101
|
+
| `src/test/__snapshots__/*.snap` | Committed HTML snapshots asserted by the Storybook test-runner (see [Getting Started](../getting-started.md)). |
|
|
102
|
+
| `src/test/snapshot-resolver.js`, `src/test/snapshot-serializer.js` | Custom Jest snapshot resolver/serializer wiring referenced from `test-runner-jest.config.js`. |
|
|
103
|
+
|
|
104
|
+
## Build & tooling config
|
|
105
|
+
|
|
106
|
+
| File | Description |
|
|
107
|
+
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
|
+
| `rollup.config.ts` | The npm build: entry `src/index.ts` → `lib/index.cjs.js` (CJS) + `lib/index.esm.js` (ESM), both with `inlineDynamicImports: true` (single-chunk output); externalizes `react`/`react-dom`; extracts styles to `lib/bundle.css` via `rollup-plugin-postcss`; minifies via `rollup-plugin-terser`; type declarations via `rollup-plugin-typescript2`. |
|
|
109
|
+
| `tsconfig.json` | `strict: true` but `noImplicitAny` is not enabled — see [Deep Dive → Failure modes](deep-dive.md#6-failure-modes--sharp-edges). |
|
|
110
|
+
| `.babelrc`, `postcss.config.js` | Babel preset config (used by `react-scripts`/Storybook webpack path) and PostCSS preset-env config for the Rollup CSS extraction. |
|
|
111
|
+
| `scripts/buildUtils.js`, `scripts/frankBuild.js` | Supporting build scripts invoked around the Rollup build. |
|
|
112
|
+
| `.storybook/main.ts` | Storybook 8 config (webpack5 + CRA preset, addons: essentials, interactions, a11y, styling-webpack, Chromatic). |
|
|
113
|
+
| `.storybook/preview.ts`, `.storybook/manager.ts` | Storybook preview/manager UI customization. |
|
|
114
|
+
| `.storybook/test-runner.ts` | Configures `@storybook/test-runner`'s `postVisit` hook to snapshot each story's rendered `innerHTML` after animations settle (`TRANSITION_DURATION` / `WIDGET_MINIMIZE_ANIMATION_DURATION`). This is the repo's only automated test coverage — see [Deep Dive → Failure modes](deep-dive.md#6-failure-modes--sharp-edges). |
|
|
115
|
+
| `test-runner-jest.config.js` | Jest config layered on top of `@storybook/test-runner`'s default config; wires the custom snapshot resolver/serializer from `src/test/`. |
|
|
116
|
+
| `chromatic.config.json` | Chromatic (visual regression / Storybook publish) project config, used by `npm run chromatic`. |
|
|
117
|
+
| `.eslintignore`, `.prettierignore`, `.prettierrc` | Lint/format scope and formatting rules (`@trivago/prettier-plugin-sort-imports` enforces import ordering — do not hand-reorder imports). |
|
|
118
|
+
| `.husky/pre-commit`, `.husky/commit-msg` | Git hooks: pre-commit runs lint + format + install + full Rollup build (see [Deep Dive → Failure modes](deep-dive.md#6-failure-modes--sharp-edges) for why this is slow/bypassable). |
|