@octane-xplat/date-picker 0.9.0 → 0.10.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 +117 -10
- package/dist/native/octane-client-build.json +1 -1
- package/package.json +6 -6
- package/src/AppKitDatePicker.macos.tsrx +1 -1
- package/dist/web/DateInput.web.tsrx.js +0 -57
- package/dist/web/octane-client-build.json +0 -8
- package/dist/web/web/index.js +0 -2
- package/src/DateInput.web.tsrx +0 -30
- package/src/web/index.ts +0 -2
- package/src/web/types.ts +0 -20
- package/types/web/index.d.ts +0 -18
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
|
|
6
|
-
|
|
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`,
|
|
11
|
-
from `@octane-xplat/date-picker/
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
|
21
|
-
|
|
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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octane-xplat/date-picker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.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
|
-
"./
|
|
27
|
-
"types": "./types/
|
|
28
|
-
"
|
|
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.
|
|
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
|
|
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,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 };
|
package/dist/web/web/index.js
DELETED
package/src/DateInput.web.tsrx
DELETED
|
@@ -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
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
|
-
}
|
package/types/web/index.d.ts
DELETED
|
@@ -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
|