East Blue
KeepReady
Date Picker - Calendar Component link

The calendar surface itself. Three modes — a day grid, a month list and a year list — assembled entirely from Date Picker - Cell and Date Picker - Header instances.

Keep — composed, not redrawn
All four DS Health traits pass. The previous calendar was a from-scratch redraw with raster chevrons, weekday-named layers, a missing Month chevron and a misleading Type setting. This one is built from Date Picker - Cell and Date Picker - Header instances, the chevrons are icon instances, and Mode = Day | Year | Month uses the same words the native APIs do. It is badged Needs Refinement for the scroll indicator it draws itself and the touch targets it inherits from the cell.
In Context

Appears as an overlay above the field once a date picker is opened. Day mode is the default; tapping the month or year chip in its header switches to the corresponding list, and the back chevron returns.

Live Preview
Properties
Mode
hasWeek6
DS Health
Reusable
Pass
One surface serves all three views. Nothing about a particular month or year is baked into the component.
Self-contained
Pass
Carries its own card surface, border, radius, header layout and grid spacing. Everything inside it is an instance of a sibling component.
Consistent
Pass
All three modes read Header → Content, and the rows are Row in every mode. The centre of the header names its own role — Container when it holds the chips, Title when it holds static text.
Composable
Pass
Assembled from Date Picker - Cell, Date Picker - Header and Date Picker - Header Trigger. Sits inside Date Picker as its overlay.
Behavior
State iOS Android Figma Property Notes
Mode=Day N/A N/A 312 × 336 Weekday row plus six rows of seven cells. Header pages through months.
Mode=Month N/A N/A 312 × 296 Twelve cells in a three-column grid. Header shows a back chevron and a title.
Mode=Year N/A N/A 312 × 296 Eighteen cells, scrollable. Header shows a back chevron and a title.
Header chevrons N/A N/A Chevron Left / Right Previous and next month in Day mode; back in Month and Year.
Issues
  • The row-count setting is named for what it does. It was week 6 — lowercase, with a space, and named as a noun rather than a state. It is now hasWeek6, matching hasCaret on Header Trigger. A dropdown of 4, 5 and 6 was considered and rejected: Figma has no enum that is not a variant, so it would have turned three components into nine. The boolean stays, and the native side counts rows instead. C2 · Variant & Property Naming
  • The Title frame no longer paints twice. The Month and Year header carried a white fill on an already-white card and an #E5EBF4 stroke switched off. Neither drew anything, but both read as surfaces when inspecting the layers. Cleared in Figma during this run — the fourth and last of these leftovers in the family. C1 · Layer Structure & Naming
  • The calendar is assembled, not redrawn. Every cell in every mode is a Date Picker - Cell instance, and the weekday strip is seven Date Picker - Header instances. The old surface drew its own cells, which is why cell states were undefined on the grid. C1 · Layer Structure & Naming
  • Layers are named by role, not by weekday. Day cells were previously named after the weekday they happened to fall on, which broke as soon as the month started on a different day. Rows are now Row and cells are Picker Cell instances throughout. C1 · Layer Structure & Naming
  • The mode setting uses native words. Type = Date | Year | Month became Mode = Day | Year | Month. "Date" described the whole component rather than the view; "Day" matches what both platforms call it. C2 · Variant & Property Naming
  • The chevrons are icon instances. They were raster shape_full assets that could not recolour or scale. Both are now Chevron Left and Chevron Right icon instances, and Month gained the previous-chevron it was missing entirely. C6 · Asset & Icon Quality
  • Cell states are defined by the cell. The grid used to have no way to express a pressed, selected or disabled day. Those now come from Date Picker - Cell's own settings, so the surface does not need to know about them. C5 · Interaction State Coverage
  • The header centre names its own role. Day mode's centre is a Container holding two chips; Month and Year use a Title holding static text. Reading the layer name now tells you which of the two header behaviours you are looking at. C4 · Native Mappability
  • The grid content is correct. The day grid previously repeated the 21st across two rows and filled its last row with cells reading "0". It now runs 1 to 31 with the trailing row showing the next month's days in the Prev-Next treatment. C1 · Layer Structure & Naming
Recommendations
  • Take the row, not the cell, for range continuity. v2.1: Closed — decided against, matching the same call on Date Picker - Cell. The strip bleeds past the cell on purpose so the highlight meets its neighbour and reads as one bar across the row; moving it to the row would mean the row deciding which days are in range, which is the cell's job. Composition
  • Expose the grid as a grid to assistive tech. v2.1: Applied — Accessibility carries both halves of the ask: the grid is announced as a grid so a screen reader user can move by week as well as by day, and the decorative weekday strip is hidden. A11y
  • Document that the chevrons change meaning by mode. v2.1: Applied — Accessibility spells both behaviours out for each platform: "Previous month" and "Next month" in Day, "Back" in Month and Year. Month and Year carry no right chevron at all, which the Style tab now renders correctly. Docs
  • Drop the drawn scroll indicator before handoff. v2.1: Applied — a Usage Guideline now pairs "let the platform draw scroll indicators in Year mode" with "don't build the drawn scrollbar from the Figma file", and the scorecard records that the Scrollbar is a shared component instance mapping to the platform indicator, not a rectangle to reproduce. Docs
  • Rename the component to Date Picker - Calendar in Figma. v2.1: Applied — node 6769:105110 reads Date Picker - Calendar. The recommendation also asked that the field trigger be renamed after this one; that is still outstanding on date-picker (node 7201:112099) and carries over to its own review. Rename
Modes
Day
Properties
hasWeek6
Properties
Mode Day
hasWeek6 true
Rows 1 weekday + 6 week
Versions 3
Colors
Card surface #FFFFFF
Card border #E5EBF4
Chevron Left / Right #005CE5
Typography
Header Trigger · #text Primary/Label/Base
Header · #text Primary/Label/Small
Cell · #text Primary/Label/Light/Small
Layout
Height 336px
Width 312px
Radius 8px
Padding H 16px
Padding V 16px
Gap 8px
Alignment Center
Colors

The calendar paints only three things of its own — the card, its border and the two chevrons. Everything inside is a Date Picker - Cell, - Header or - Header Trigger instance carrying its own colours; the scrollbar in Year mode is a shared Scrollbar component. No states: the surface never changes.

Role Token Value
Card surface bg/color-bg-primary-inverse #FFFFFF
Card border border/color-border-weak #E5EBF4
Chevron Left / Right border/color-border-primary #005CE5
Scrollbar thumb — Year text/color-text #0A2757
Month
Properties
Mode Month
Cells 12 — 3 columns × 4 rows
Versions 3
Colors
Card surface #FFFFFF
Card border #E5EBF4
Chevron Left / Right #005CE5
Typography
Title · #text Primary/Label/Base
Cell · #text Primary/Label/Light/Small
Layout
Height 296px
Width 312px
Radius 8px
Padding H 16px
Padding V 16px
Gap 8px header → content · 32px between rows, 16px between columns
Alignment Center
Year
Properties
Mode Year
Cells 18 — 3 columns × 6 rows, scrolled
Versions 3
Colors
Card surface #FFFFFF
Card border #E5EBF4
Chevron Left / Right #005CE5
Typography
Title · #text Primary/Label/Base
Cell · #text Primary/Label/Light/Small
Layout
Height 296px
Width 312px
Radius 8px
Padding H 16px
Padding V 16px
Gap 8px header → content · 32px between rows, 16px between columns
Alignment Center
Installation Planned API

iOS — Swift Package Manager

.package(url: "https://github.com/AY-Org/eb-ds-ios", from: "1.0.0")

Android — Gradle (Kotlin DSL)

implementation("com.eastblue.ds:date-picker:1.0.0")

Import

import EastBlueDS
import com.eastblue.ds.datepicker.*

Planned API — the native library does not exist yet. The artifact is the Date Picker family, not this component: Cell, Header, Header Trigger, Calendar and the picker itself all ship in <code>com.eastblue.ds:date-picker</code> and import <code>com.eastblue.ds.datepicker.*</code>.

Property Mapping

Two properties. Everything else on this component is a nested instance rather than a setting: the header chevrons, the two Header Trigger chips, the weekday row and every date cell are Date Picker instances that carry their own properties. hasWeek6 is the one place Figma and the platform disagree in shape — Figma toggles a row, the platform counts them, because a February that starts on the first day of the week needs four.

Figma PropertySwiftUICompose
Mode — Day, Month, Year mode: EBDatePickerCalendarMode mode: EBDatePickerCalendarMode
hasWeek6 — true, false weeks: Int = 6 — the boolean is a row count on both platforms, clamped to 4...6 weeks: Int = 6 — same, clamped to 4..6
Usage Snippets Planned API
Day — the month grid
EBDatePickerCalendar(
    mode: .day,
    weeks: 6
)
EBDatePickerCalendar(
    mode = EBDatePickerCalendarMode.Day,
    weeks = 6
)
Month — the twelve-month list
EBDatePickerCalendar(
    mode: .month
)
EBDatePickerCalendar(
    mode = EBDatePickerCalendarMode.Month
)
Year — the scrolling year list
EBDatePickerCalendar(
    mode: .year
)
EBDatePickerCalendar(
    mode = EBDatePickerCalendarMode.Year
)
Accessibility
RequirementiOSAndroid
The grid is announced as a grid .accessibilityElement(children: .contain) with row and column traits Modifier.semantics { collectionInfo = CollectionInfo(rows, 7) }
Weekday strip is hidden .accessibilityHidden(true) — each cell names its own weekday Modifier.clearAndSetSemantics {}
Mode changes are announced UIAccessibility.post(.screenChanged) on switching mode LiveRegionMode.Polite on the header title
Chevrons are labelled by what they do "Previous month" and "Next month" in Day; "Back" in Month and Year Same, via contentDescription
Dynamic type Supported, scales to AX5 — the 312pt card is fixed, so the grid keeps its columns and the cells truncate rather than reflow sp units; the 312dp card behaves the same way
Usage Guidelines

Do

Let the platform's calendar supply locale, first-day-of-week and date arithmetic.

Don't

Don't reimplement the calendar maths to match this Figma grid exactly.

Do

Open Day mode first and treat Month and Year as drill-downs from the header.

Don't

Don't expose Mode as a user-facing toggle — it is navigation state.

Do

Let the platform draw scroll indicators in Year mode.

Don't

Don't build the drawn scrollbar from the Figma file.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready Header → Content → Row, with every cell an instance. Grid content is correct.
C2 Variant & Property Naming Ready Mode = Day | Year | Month matches native terminology.
C3 Token Coverage Ready All four roles the calendar paints itself are bound and confirmed by design: the card surface, its border, the two chevrons and the Year scrollbar. Everything inside carries the tokens of the instance that draws it.
C4 Native Mappability Ready The card maps to a calendar view on both platforms. The scrollbar is a shared Scrollbar component, not a drawn rectangle, and maps to the platform indicator. hasWeek6 is the one shape difference: Figma toggles a row, the platform counts them, so it maps to weeks: Int clamped to 4...6.
C5 Interaction State Coverage Ready Every state comes from the cell, which is the only interactive part. The 32 × 32 cell and the 24px header chip are deliberate visual sizes with tap targets expanded natively to 44 pt / 48 dp, as settled on those components.
C6 Asset & Icon Quality Ready Chevrons are icon instances; the rasters are gone.
Variants Inventory (3 total)

1 Mode setting × 3 values. Everything else varies by the instances placed inside.

ModeSizeContentHeader centreNode
Day312 × 3367 weekday + 42 cells2 Header Trigger6769:105099
Month312 × 29612 cellsTitle6769:105109
Year312 × 29618 cells + scroll indicatorTitle6769:105100
2.1.0 — September 2026Minor
hasWeek6 renamed, Style and Code tabs rebuilt — node 6769:105110
The row-count setting is named for what it does. week 6 became hasWeek6 — lowercase, a space, and a noun where a state belonged. A Weeks = 4, 5, 6 dropdown was weighed and rejected: Figma has no enum that is not a variant, so it would have taken the set from three components to nine. This is what makes the release a minor rather than a patch.
C2 resolved
The Title frame no longer paints twice. The Month and Year header carried a white fill on an already-white card plus an #E5EBF4 stroke switched off. The fourth and last of these leftovers in the family, cleared in Figma during this run.
C1 resolved
One card became three. The Style tab had a single card switching its rows by variants; Mode is the driving property, so Day, Month and Year each get their own card. hasWeek6 is the only control left, on the Day card alone.
Docs
The documented type style did not exist. Typography read Primary/Bold/Subheading, which is not in the database, alongside a font spec and a "Cell text: supplied by Date Picker - Cell" cross-reference. Each card now lists the text layers visible in that mode with the instance that owns them: Primary/Label/Base for the Title and header chips, Primary/Label/Small for the weekday row, Primary/Label/Light/Small for the cells.
C3 resolved
Four of five colour tokens named the wrong steps — bg/color-bg-main, border/color-border-subtle, text/color-text-heading and icon/color-icon-link. The bindings are bg/color-bg-primary-inverse, border/color-border-weak, text/color-text and border/color-border-primary. The fifth was worse: the scroll indicator was recorded as #E5EBF4 with the token "annotation only — not built", when it is built and its thumb is #0A2757.
C3 resolved
Layout had none of the seven keys — Padding, Header height, Header to content, Row height, Row gap and Corner radius. All three cards now carry Height · Width · Radius · Padding H · Padding V · Gap · Alignment, with Day switching to 296px when hasWeek6 is off — the same height as Month and Year.
Docs
Five preview corrections. The chevrons were a 16px approximation at stroke 1.8 against Figma's 24px at 2; the two header chips were drawn without their carets; the Month and Year grid used a 16px row gap and no column gap where Figma has 32 and 16; the scrollbar was #E5EBF4 at 120px against #0A2757 at 80px; and the card declared no font-family, so it rendered in the documentation font rather than Proxima Soft.
Docs
The install block pointed at coordinates that will never exist. gcash/east-blue-ios and com.gcash.eastblue:components:1.0.0, with no Import line. It now cites the family artifact com.eastblue.ds:date-picker:1.0.0 and imports com.eastblue.ds.datepicker.*.
Docs
Property Mapping listed layers as properties. Four of its five rows were nested instances — the chevrons, the two Header Trigger chips, the cells and the scrollbar — while hasWeek6 was missing entirely. Two rows now, for the two real properties. hasWeek6 maps to weeks: Int clamped to 4...6: Figma toggles a row, the platform counts them, because a February starting on the first day of the week needs four.
C4 resolved
Usage Snippets were keyed to scenarios, not to the driving property. They showed "as the overlay of a date field" and "selecting a range", and between them used three spellings of one enum — CalendarMode, mode: CalendarMode and EBDatePickerCalendarMode. One snippet per Mode now, built from the same definition as the spec cards and the live preview.
Docs
Two scorecard notes had gone stale. C3 said only the surface and border were bound; all four roles are bound and confirmed. C4 said the drawn scrollbar maps to nothing; it is a shared Scrollbar component that maps to the platform indicator. C5 inherited the 32 × 32 cell and 24px chip as open concerns, both since settled as deliberate. C3, C4 and C5 all move to Ready.
C5 resolved
Code Connect was populated on a component with nothing registered. Three rows claimed readiness against a native library that does not exist. The section is gone; C7 stays Not Mapped. Accessibility gained a Dynamic Type row, and a getSnippet keeps the DEV code live.
Docs
All five recommendations are closed. The rename landed; the scroll indicator, the chevrons' two behaviours and the grid semantics are documented for both platforms; and the range-continuity ask is closed as decided against, matching the same call on Date Picker - Cell. The one thing carried forward is the second half of the rename note — the field trigger at node 7201:112099 still takes the Date Picker name.
Docs
2.0.0 — August 2026Major
Rebuilt as a composed surface — node 6769:105110
Replaces Date Picker - Group. The calendar is now assembled from Date Picker - Cell and Date Picker - Header instances rather than redrawn.
Family
C2 — Type became Mode = Day | Year | Month, matching what both platforms call these views.
C2 resolved
C6 — raster chevrons replaced with icon instances, and Month gained the previous-chevron it never had.
C6 resolved
C1 — layers named by role. Weekday-named day cells became Picker Cell instances inside Row frames; content-container and row were recased to Container and Row.
C1 resolved
C1 — grid content corrected. The duplicated 21st and the row of cells reading "0" are gone; the trailing row now shows the next month in the Prev-Next treatment.
C1 resolved
C4 — the header centre names its role: Container when it holds the chips, Title when it holds static text.
C4 resolved
C4 — the drawn scroll indicator stays as a visual spec note for handover, not as something to build.
C4 partial