sam-datepicker-v2 renders unstyled: .datepicker__* CSS was lost in the 2019 fork
- Dominant language
- TypeScript
- Stars
- 8
- Forks
- 33
- Avg merge
- 2d 51m
- Merged PRs (30d)
- 65
Description
`sam-datepicker-v2` renders with no styling at all. Its template asks for a full set of bespoke `.datepicker__*` classes that **are not defined in any stylesheet** — not in this repo, not in `sam-styles/`, not in `@gsa-sam/sam-styles`, and not in any `node_modules` of either workspace.
Measured on the `/datepicker` gallery route added in #666 (Chromium, real browser):
```
popup: 684 x 2081 px
.datepicker__calendar position: static (needs absolute)
.datepicker__calendar__month__day display: block, width: 684px
```
Day cells stack vertically down the page instead of forming a 7-column grid, and the popup is not positioned over the input.
## Root cause
`sam-datepicker-v2` is a fork of [`angular2-material-datepicker`](https://www.npmjs.com/package/angular2-material-datepicker) (MIT). The animation trigger is byte-identical, keyframe offsets and all:
```ts
// upstream and SAM, identical
trigger('calendarAnimation', [
transition('* => left', [ animate(180, keyframes([
style({ transform: 'translateX(105%)', offset: 0.5 }),
style({ transform: 'translateX(-130%)', offset: 0.51 }),
style({ transform: 'translateX(0)', offset: 1 }) ]))]),
```
Upstream carried its CSS **inline** in `styles: [...]` — 25 `.datepicker__*` rules, including the structural ones:
```css
.datepicker { position: relative; display: inline-block; }
.datepicker__calendar { position: absolute; overflow: hidden; z-index: 1000;
top: 1.9em; left: 0; height: 24.25em; width: 20.5em;
background-color: #fff; box-shadow: 0 3px 6px rgba(0,0,0,.16), 0 3px 6px rgba(0,0,0,.23); }
```
SAM's fork (`3ba95ec0`, Feb 2019, "PR for adding date range component related to IAE-14621" #263) moved the inline template out to `picker.template.html` and **dropped the `styles:` block entirely**, without re-adding it to either the component or `sam-styles/`. The class names came along, so the markup still requests CSS that has never existed in this repo. `date-range-v2.component.scss` has been **0 bytes since that same commit** and `picker.component.ts` has no `styleUrls`.
## Why this went unnoticed for ~7 years
Nothing rendered it. `test-app` could not render any library component until #665, and the sole tracked consumer does not use this component:
- `scripts/consumer-deep-imports.json` tracks 3 consumers, all the same app (`iae-sam-front-end`, `-front-end3`, `-front-end-uat`).
- Zero occurrences of `sam-datepicker-v2` or `sam-date-range-v2` in that app's source. It uses the **stable** control instead: 32x ``, 8x ``.
- `SamUIKitModule` -> `SamExperimentalModule` does register `SamDateRangeV2Module`, so it is compiled into the consumer bundle and available in templates — just never used.
- Five other SAM frontends checked (`-search`, `-admin`, `-integrity`, `-systemaccounts`, `-role-management-service`) do not depend on `sam-ui-elements` at all.
Contrast with the stable `sam-date`, which also has no `styleUrls` but whose markup uses **USWDS** classes (`usa-form-group`, `usa-form-control`) that every consumer already loads globally. That is why `sam-date` renders fine with no CSS from this library and `sam-datepicker-v2` does not.
## Decision needed first
Given zero known consumers, "write calendar CSS" may not be the right answer. Pick one:
1. **Restore the lost upstream CSS** as component `styleUrls` (matches `experimental/tabs`, which does self-style; Angular's `_ngcontent` scoping avoids any global-namespace collision). Upstream is MIT — attribute it.
2. **Add it to `sam-styles/themes/sam-gov`**, matching the library's dominant global-CSS model (that is how `iae-sam-front-end` styles the kit: `@import '@gsa-sam/sam-ui-elements/sam-styles/themes/sam-gov'`). Riskier — global namespace.
3. **Deprecate `date-range-v2`.** It is `experimental/`, forked, unstyled, and unused. Removal is a breaking change for the deep-import contract, so check `scripts/consumer-deep-imports.json` first (it currently lists no `date-range-v2` paths).
## Two smaller, separable gaps
These are legitimately the consumer's responsibility, but the harness needs them for manual testing either way:
- **`.fa fa-calendar`** — a SAM addition (upstream had no icon; it clicked the input). `@fortawesome/fontawesome-free` is a root **peerDependency**, so consumers load the webfont CSS. `test-app` has only `fontawesome-svg-core` (JS/SVG API), so no glyph renders.
- **`.sr-only`** — Bootstrap-era class. `@gsa-sam/sam-styles` ships only USWDS `.usa-sr-only`, so nothing defines it and the screen-reader label renders as the visible text "Calendar" next to the input.
## Acceptance criteria
- [ ] A decision is recorded on options 1/2/3 above
- [ ] If styling: `.datepicker`, `.datepicker__calendar`, nav/arrow/chevron, `__labels`/`__label`, `__month`/`__month__day`, and `__cancel` all render as a positioned 7-column calendar overlay
- [ ] If styling: upstream MIT attribution is included alongside the restored rules
- [ ] `test-app` loads FontAwesome webfont CSS and an `.sr-only` rule so `/datepicker` is manually testable without DevTools injection
- [ ] Playwright assertions cover the cascade-level properties jsdom cannot see (`position: absolute` on the popup, popup width, day-cell width ~14.28%) — per AGENTS.md's Vitest/Playwright boundary
- [ ] **The existing open-click guard in `test-app/e2e/datepicker.spec.ts` still fails when the `contains()` fix in `picker.component.ts` is reverted.** It clicks the `.sr-only` child explicitly for exactly this reason; adding an `.sr-only` rule collapses that span to 1x1, and a centre click on `.fa-calendar` would pass even with the defect reintroduced. Verify by reverting the fix locally.
## Context
Found while manually testing #666, which added the `/datepicker` gallery route — the first time this component had ever been rendered in a browser in CI or locally. Deliberately kept out of #666 to hold that PR to its two event-handling fixes.
Contributor guide
Research direction
First compare picker.component.ts, picker.template.html, and date-range-v2.component.scss with the upstream component, then review scripts/consumer-deep-imports.json and the three proposed paths. Run the /datepicker gallery and test-app/e2e/datepicker.spec.ts; done means the chosen decision is recorded, the calendar cascade and accessibility setup are testable, and the Playwright assertions pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, playwright, sass, typescript
- Domain
- accessibility, frontend, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100