@octane-xplat/date-picker 0.9.0 → 0.11.0

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/README.md CHANGED
@@ -2,31 +2,138 @@
2
2
 
3
3
  An install boundary for platform-specific date and time selection controls:
4
4
  a SwiftUI `DatePicker` on iOS, Material 3 `DatePicker`/`TimePicker` built with
5
- Jetpack Compose on Android, a labeled `<input type="date|time|datetime-local">`
6
- on web, and a real `NSDatePicker` on macOS.
5
+ Jetpack Compose on Android, and a real `NSDatePicker` on macOS. For portable
6
+ form controls, use `Calendar`, `DateInput`, `TimeInput`, `DateTimeInput`, and
7
+ `DateRangeInput` from `@octane-xplat/ui` on every target.
8
+
9
+ ```tsx
10
+ import { useState } from 'octane'
11
+ import { DateInput } from '@octane-xplat/ui'
12
+
13
+ export function DepartureDate() {
14
+ const [date, setDate] = useState<string | null>('2026-10-02')
15
+ return <DateInput value={date} onChange={setDate} label="Departure" />
16
+ }
17
+ ```
7
18
 
8
19
  Install the package in the app that renders a control. Import
9
20
  `SwiftUIDatePicker` from `@octane-xplat/date-picker/ios`,
10
- `MaterialDatePicker` from `@octane-xplat/date-picker/android`, `DateInput`
11
- from `@octane-xplat/date-picker/web`, or `AppKitDatePicker` from
12
- `@octane-xplat/date-picker/macos` in the matching platform-suffixed file.
13
- Each entry exports its own component and types; there is no shared date-picker
14
- API at the package root.
21
+ `MaterialDatePicker` from `@octane-xplat/date-picker/android`, or
22
+ `AppKitDatePicker` from `@octane-xplat/date-picker/macos` in the matching
23
+ platform-suffixed file. These native entries have platform-specific contracts.
24
+ The old `@octane-xplat/date-picker/web` `DateInput` subpath was removed because
25
+ its browser-only string contract conflicted with the shared `DateInput` API.
26
+
27
+ ```tsx
28
+ /** @jsxImportSource @nativescript-community/octane */
29
+ // SwiftUIDatePickerExample.ios.tsx
30
+ import { SwiftUIDatePicker } from '@octane-xplat/date-picker/ios'
31
+
32
+ export function Picker() {
33
+ return (
34
+ <SwiftUIDatePicker
35
+ defaultSelection={new Date(2026, 9, 2)}
36
+ displayedComponents={['date']}
37
+ pickerStyle="graphical"
38
+ onSelectionChange={console.log}
39
+ />
40
+ )
41
+ }
42
+ ```
43
+
44
+ ```tsx
45
+ /** @jsxImportSource @nativescript-community/octane */
46
+ // MaterialDatePickerExample.android.tsx
47
+ import { MaterialDatePicker } from '@octane-xplat/date-picker/android'
48
+
49
+ const initialDate = new Date(2026, 9, 2)
50
+ const bounds = { start: new Date(2026, 0, 1), end: new Date(2026, 11, 31) }
51
+
52
+ export function Picker() {
53
+ return (
54
+ <MaterialDatePicker
55
+ initialDate={initialDate}
56
+ selectableDates={bounds}
57
+ onDateSelected={console.log}
58
+ />
59
+ )
60
+ }
61
+ ```
62
+
63
+ ```tsx
64
+ // AppKitDatePickerExample.macos.tsx
65
+ import { AppKitDatePicker } from '@octane-xplat/date-picker/macos'
66
+
67
+ export function Picker() {
68
+ return (
69
+ <AppKitDatePicker
70
+ components="date"
71
+ pickerStyle="graphical"
72
+ defaultSelection={new Date(2026, 9, 2)}
73
+ onSelectionChange={console.log}
74
+ />
75
+ )
76
+ }
77
+ ```
15
78
 
16
79
  The platform APIs use their own selection vocabulary: the iOS entry takes a
17
80
  controlled `selection`/`defaultSelection` `Date` with `displayedComponents`
18
81
  and `pickerStyle`; the Android entry follows the uncontrolled
19
82
  `initialDate`/`onDateSelected` model of the Material 3 pickers with
20
- `selectableDates` range bounds; the web entry follows browser input values;
21
- the macOS entry takes `components`/`pickerStyle` (`'graphical'` embeds the
83
+ `selectableDates` range bounds; the macOS entry takes
84
+ `components`/`pickerStyle` (`'graphical'` embeds the
22
85
  inline calendar) with a controlled `selection` `Date`.
23
86
 
87
+ ```tsx
88
+ // Departure.macos.tsx
89
+ import { useState } from 'octane'
90
+ import { AppKitDatePicker } from '@octane-xplat/date-picker/macos'
91
+
92
+ export function Departure() {
93
+ const [selection, setSelection] = useState(new Date(2026, 9, 2))
94
+ return (
95
+ <AppKitDatePicker
96
+ components="date"
97
+ pickerStyle="graphical"
98
+ selection={selection}
99
+ onSelectionChange={setSelection}
100
+ />
101
+ )
102
+ }
103
+ ```
104
+
24
105
  Android notes: give `MaterialDatePicker` a bounded height (the M3 calendar's
25
106
  lazy grid collapses under unbounded height), and keep `initialDate` and
26
107
  `selectableDates` identity-stable — the provider keys its state `remember`
27
108
  on them, so a per-render `new Date()` resets the selection.
28
109
  See the framework guide for details and maintained examples:
29
- [`docs/date-picker.md`](../../docs/date-picker.md).
110
+ [`docs/platform/date-picker.md`](../../docs/platform/date-picker.md).
111
+
112
+ ```tsx
113
+ /** @jsxImportSource @nativescript-community/octane */
114
+ // Departure.android.tsx — reuse these objects while the picker is mounted.
115
+ import { MaterialDatePicker } from '@octane-xplat/date-picker/android'
116
+
117
+ const initialDate = new Date(2026, 9, 2)
118
+ const selectableDates = { start: new Date(2026, 0, 1) }
119
+ export function Departure() {
120
+ return (
121
+ <MaterialDatePicker
122
+ className="departure-calendar"
123
+ initialDate={initialDate}
124
+ selectableDates={selectableDates}
125
+ onDateSelected={console.log}
126
+ />
127
+ )
128
+ }
129
+ ```
130
+
131
+ ```css
132
+ /* App stylesheet: give the Android calendar room for its grid. */
133
+ .departure-calendar {
134
+ height: 480px;
135
+ }
136
+ ```
30
137
 
31
138
  The native implementations are adapted from `@expo/ui` (MIT,
32
139
  `packages/expo-ui` sdk-57): `ios/DatePickerView.swift` and
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 1,
3
- "buildId": "1fb9fdab-32f1-4d82-ad87-ffe708c70839",
3
+ "buildId": "8ce7a66c-b566-4cba-a2a1-e4f42c86a3af",
4
4
  "mode": "production",
5
5
  "capabilities": {
6
6
  "independentHydration": false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octane-xplat/date-picker",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Platform-specific date and time selection controls for Octane xplat",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,9 +23,9 @@
23
23
  "types": "./types/android/index.d.ts",
24
24
  "native": "./dist/native/android/index.js"
25
25
  },
26
- "./web": {
27
- "types": "./types/web/index.d.ts",
28
- "web": "./dist/web/web/index.js"
26
+ "./macos": {
27
+ "types": "./types/macos/index.d.ts",
28
+ "macos": "./src/macos/index.ts"
29
29
  }
30
30
  },
31
31
  "publishConfig": {
@@ -40,7 +40,7 @@
40
40
  "@nativescript/core": "9.1.2",
41
41
  "@octanejs/vite-plugin": "0.1.60",
42
42
  "octane": "0.5.0",
43
- "tsrx-typegen": "0.2.1",
43
+ "tsrx-typegen": "0.2.2",
44
44
  "typescript": "5.9.3",
45
45
  "vite": "8.3.0"
46
46
  },
@@ -67,7 +67,7 @@
67
67
  }
68
68
  },
69
69
  "scripts": {
70
- "build": "vite build && vite build --mode native && tsc -p tsconfig.types.json",
70
+ "build": "vite build --mode native && tsc -p tsconfig.types.json",
71
71
  "test:packed": "node tests/packed-consumer.mjs",
72
72
  "pack:check": "tsrx-typegen --pack-check"
73
73
  }
@@ -1,4 +1,4 @@
1
- /** @jsxImportSource @xplat/macos/renderer */
1
+ /** @jsxImportSource @octane-xplat/macos-renderer */
2
2
  import { useEffect, useRef } from 'octane'
3
3
  import type { AppKitDatePickerProps } from './macos/types'
4
4
 
@@ -1,57 +0,0 @@
1
- import { __s, bag16, child, clone, delegateEvents, hookSlots, setAriaAttribute, setBooleanAttribute, setEventHandler, setStyle, sibling, template, useState } from "octane";
2
- import { bindSignalAttribute, bindSignalChild, bindSignalValue, enableSignalBindings, setPlainAttribute } from "octane/internal/client";
3
- //#region src/DateInput.web.tsrx
4
- enableSignalBindings(1, true);
5
- delegateEvents(["change"]);
6
- var _t$0 = /* @__PURE__ */ template("<label><span></span><input data-octane-input=\"i:ca76d877\"/></label>");
7
- var _hs$ = /* @__PURE__ */ hookSlots(1);
8
- var DateInput = /* @__PURE__ */ __s(function DateInput(props, __s, __extra) {
9
- const controlled = props.value !== void 0;
10
- const [internalValue, setInternalValue] = useState(props.defaultValue ?? "", _hs$ + 0);
11
- const value = controlled ? props.value : internalValue;
12
- const labelId = props.id ? `${props.id}-label` : void 0;
13
- if (__s.block.pending && !__s.block.crossRenderUpdate) return;
14
- let _b = __s.slots[0];
15
- if (_b === void 0) {
16
- let _m1, _m4, _m6, _m10;
17
- const _root = clone(_t$0);
18
- _m1 = _root;
19
- const _el0 = child(_root);
20
- _m4 = _el0;
21
- const _el1 = sibling(_el0, 1);
22
- _m6 = _el1;
23
- _m10 = bindSignalValue(__s, void 0, _el1, value, "i:ca76d877");
24
- setEventHandler(_el1, "$$change", (event) => {
25
- const nextValue = event.target.value;
26
- if (!controlled) setInternalValue(nextValue);
27
- props.onChange?.(nextValue);
28
- });
29
- _b = bag16(__s, _root, void 0, _m1, void 0, void 0, _m4, void 0, _m6, void 0, void 0, void 0, _m10, void 0, void 0, void 0, null, void 0);
30
- } else {
31
- _b.k = bindSignalValue(__s, _b.k, _b.g, value, "i:ca76d877");
32
- setEventHandler(_b.g, "$$change", (event) => {
33
- const nextValue = event.target.value;
34
- if (!controlled) setInternalValue(nextValue);
35
- props.onChange?.(nextValue);
36
- });
37
- }
38
- _b.a = bindSignalAttribute(__s, _b.a, _b.b, "class", props.className, "b:cabeae14", "class");
39
- {
40
- const _v = props.style;
41
- if (_b.c !== _v) {
42
- setStyle(_b.b, _v, _b.c);
43
- _b.c = _v;
44
- }
45
- }
46
- _b.d = bindSignalAttribute(__s, _b.d, _b.e, "id", labelId, "b:6dc088f1", setPlainAttribute);
47
- _b.f = bindSignalAttribute(__s, _b.f, _b.g, "id", props.id, "b:f74893e7", setPlainAttribute);
48
- _b.h = bindSignalAttribute(__s, _b.h, _b.g, "type", props.type ?? "date", "b:47e366ba", setPlainAttribute);
49
- _b.i = bindSignalAttribute(__s, _b.i, _b.g, "aria-label", props.accessibilityLabel ?? props.label, "b:a953fab4", setAriaAttribute);
50
- _b.j = bindSignalAttribute(__s, _b.j, _b.g, "aria-labelledby", labelId, "b:10bc1230", setAriaAttribute);
51
- _b.l = bindSignalAttribute(__s, _b.l, _b.g, "min", props.min, "b:4fe4c70f", setPlainAttribute);
52
- _b.m = bindSignalAttribute(__s, _b.m, _b.g, "max", props.max, "b:4c98be11", setPlainAttribute);
53
- _b.n = bindSignalAttribute(__s, _b.n, _b.g, "disabled", props.disabled, "b:701d5b16", setBooleanAttribute);
54
- _b.q = bindSignalChild(__s, _b.q, 1, _b.e, props.label, "b:25c6cb91", null, void 0, void 0, void 0, true);
55
- });
56
- //#endregion
57
- export { DateInput };
@@ -1,8 +0,0 @@
1
- {
2
- "version": 1,
3
- "buildId": "f258a4ce-175f-4808-aeed-e9a10c1bcf3e",
4
- "mode": "production",
5
- "capabilities": {
6
- "independentHydration": false
7
- }
8
- }
@@ -1,2 +0,0 @@
1
- import { DateInput } from "../DateInput.web.tsrx.js";
2
- export { DateInput };
@@ -1,30 +0,0 @@
1
- /** @jsxImportSource octane */
2
- import { useState } from 'octane'
3
- import type { DateInputProps } from './web/types'
4
-
5
- /** Renders a labeled browser date/time input. */
6
- export function DateInput(props: DateInputProps) @{
7
- const controlled = props.value !== undefined
8
- const [internalValue, setInternalValue] = useState(props.defaultValue ?? '')
9
- const value = controlled ? props.value! : internalValue
10
- const labelId = props.id ? `${props.id}-label` : undefined
11
-
12
- <label className={props.className} style={props.style}>
13
- <span id={labelId}>{props.label}</span>
14
- <input
15
- id={props.id}
16
- type={props.type ?? 'date'}
17
- aria-label={props.accessibilityLabel ?? props.label}
18
- aria-labelledby={labelId}
19
- value={value}
20
- min={props.min}
21
- max={props.max}
22
- disabled={props.disabled}
23
- onChange={(event: any) => {
24
- const nextValue = event.target.value as string
25
- if (!controlled) setInternalValue(nextValue)
26
- props.onChange?.(nextValue)
27
- }}
28
- />
29
- </label>
30
- }
package/src/web/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { DateInput } from '../DateInput.web.tsrx'
2
- export type { DateInputProps, DateInputType } from './types'
package/src/web/types.ts DELETED
@@ -1,20 +0,0 @@
1
- export type DateInputType = 'date' | 'time' | 'datetime-local'
2
-
3
- export interface DateInputProps {
4
- id?: string
5
- className?: any
6
- style?: any
7
- label?: string
8
- /** The `<input>` type. @default 'date' */
9
- type?: DateInputType
10
- /** Controlled value: `YYYY-MM-DD`, `HH:MM`, or `YYYY-MM-DDTHH:MM`. */
11
- value?: string
12
- defaultValue?: string
13
- /** Earliest allowed value, in the same format as `value`. */
14
- min?: string
15
- /** Latest allowed value, in the same format as `value`. */
16
- max?: string
17
- disabled?: boolean
18
- accessibilityLabel?: string
19
- onChange?: (value: string) => void
20
- }
@@ -1,18 +0,0 @@
1
- export type DateInputType = 'date' | 'time' | 'datetime-local'
2
-
3
- export interface DateInputProps {
4
- id?: string
5
- className?: any
6
- style?: any
7
- label?: string
8
- type?: DateInputType
9
- value?: string
10
- defaultValue?: string
11
- min?: string
12
- max?: string
13
- disabled?: boolean
14
- accessibilityLabel?: string
15
- onChange?: (value: string) => void
16
- }
17
-
18
- export declare function DateInput(props: DateInputProps): unknown