react-schedule-picker 1.0.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/LICENSE +21 -0
- package/README.md +268 -0
- package/dist/index.css +253 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +196 -0
- package/dist/index.d.ts +196 -0
- package/dist/index.js +956 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +906 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 innerbloo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# react-schedule-picker
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/react-schedule-picker)
|
|
4
|
+
[](https://bundlephobia.com/package/react-schedule-picker)
|
|
5
|
+
[](https://www.npmjs.com/package/react-schedule-picker)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Drag-to-select weekly schedule picker for React. Zero dependencies, fully typed, locale-aware.
|
|
9
|
+
|
|
10
|
+
**[Live Demo →](https://react-schedule-picker.vercel.app/)**
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
<SchedulePicker value={schedule} onChange={setSchedule} />
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Drag selection** — click cells, drag rectangles, or drag day/hour headers to select rows/columns
|
|
19
|
+
- **Touch support** — full mobile drag with haptic feedback
|
|
20
|
+
- **Locale-aware** — built-in `en`, `en-US`, `ko`, `ja`, `zh-CN`, `zh-TW` (week start, hour format, weekend colors, button text)
|
|
21
|
+
- **Serializable** — convert to ranges or iCalendar-style payloads for APIs and databases
|
|
22
|
+
- **Themable** — CSS custom properties, no styling library required
|
|
23
|
+
- **Zero runtime dependencies** — only React as a peer dep
|
|
24
|
+
- **Fully typed** — written in TypeScript with strict types
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install react-schedule-picker
|
|
30
|
+
# or
|
|
31
|
+
pnpm add react-schedule-picker
|
|
32
|
+
# or
|
|
33
|
+
yarn add react-schedule-picker
|
|
34
|
+
# or
|
|
35
|
+
bun add react-schedule-picker
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Import the stylesheet once at your app root:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import "react-schedule-picker/styles.css";
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { useState } from "react";
|
|
48
|
+
import { SchedulePicker, type Schedule } from "react-schedule-picker";
|
|
49
|
+
import "react-schedule-picker/styles.css";
|
|
50
|
+
|
|
51
|
+
export function Availability() {
|
|
52
|
+
const [schedule, setSchedule] = useState<Schedule>({});
|
|
53
|
+
|
|
54
|
+
return <SchedulePicker value={schedule} onChange={setSchedule} />;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `Schedule` shape is `Record<string, number[]>` — day key (`"mon"` … `"sun"`) mapped to an array of selected hours (0–23).
|
|
59
|
+
|
|
60
|
+
## Common Examples
|
|
61
|
+
|
|
62
|
+
### Localized to Korean
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<SchedulePicker locale="ko" value={schedule} onChange={setSchedule} />
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Business hours only
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<SchedulePicker
|
|
72
|
+
value={schedule}
|
|
73
|
+
onChange={setSchedule}
|
|
74
|
+
minHour={9}
|
|
75
|
+
maxHour={18}
|
|
76
|
+
visibleDays={["mon", "tue", "wed", "thu", "fri"]}
|
|
77
|
+
/>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Block out specific slots
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
const lunchBreak: Schedule = {
|
|
84
|
+
mon: [12, 13], tue: [12, 13], wed: [12, 13], thu: [12, 13], fri: [12, 13],
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
<SchedulePicker
|
|
88
|
+
value={schedule}
|
|
89
|
+
onChange={setSchedule}
|
|
90
|
+
disabledSlots={lunchBreak}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Read-only display
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
<SchedulePicker value={schedule} onChange={setSchedule} readOnly />
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Submit-style — fire only when the user finishes dragging
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<SchedulePicker
|
|
104
|
+
value={schedule}
|
|
105
|
+
onChange={setSchedule}
|
|
106
|
+
onSelectEnd={(final) => saveToServer(final)}
|
|
107
|
+
/>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Props
|
|
111
|
+
|
|
112
|
+
### Core
|
|
113
|
+
|
|
114
|
+
| Prop | Type | Default | Description |
|
|
115
|
+
|------|------|---------|-------------|
|
|
116
|
+
| `value` | `Schedule` | required | Controlled schedule value |
|
|
117
|
+
| `onChange` | `(s: Schedule) => void` | required | Fires on every change, including during drag |
|
|
118
|
+
| `onSelectEnd` | `(s: Schedule) => void` | — | Fires once when a drag completes |
|
|
119
|
+
|
|
120
|
+
### Localization
|
|
121
|
+
|
|
122
|
+
| Prop | Type | Default | Description |
|
|
123
|
+
|------|------|---------|-------------|
|
|
124
|
+
| `locale` | `"en" \| "en-US" \| "ko" \| "ja" \| "zh-CN" \| "zh-TW"` | `"en"` | Sets week start, hour format, weekend colors, and built-in text |
|
|
125
|
+
| `weekStartsOn` | `"mon" \| "sun" \| "sat"` | locale default | Override the first day of the week |
|
|
126
|
+
| `weekendHighlight` | `Record<string, string> \| "none"` | locale default | Weekend text colors. `"none"` disables highlighting |
|
|
127
|
+
| `dayLabels` | `Record<string, string>` | locale default | Custom day header labels |
|
|
128
|
+
| `messages` | `Partial<Messages>` | locale default | Override individual built-in messages |
|
|
129
|
+
|
|
130
|
+
### Display
|
|
131
|
+
|
|
132
|
+
| Prop | Type | Default | Description |
|
|
133
|
+
|------|------|---------|-------------|
|
|
134
|
+
| `dayAxis` | `"x" \| "y"` | `"x"` | `"x"`: days as columns. `"y"`: days as rows |
|
|
135
|
+
| `visibleDays` | `string[]` | locale default | Which days to show, and their order |
|
|
136
|
+
| `minHour` | `number` | `0` | Earliest hour to display |
|
|
137
|
+
| `maxHour` | `number` | `23` | Latest hour to display |
|
|
138
|
+
| `compactHourLabels` | `boolean` | `false` | Show only every 3rd hour label |
|
|
139
|
+
| `formatHour` | `(h: number) => string` | locale default | Custom hour label formatter |
|
|
140
|
+
|
|
141
|
+
### State
|
|
142
|
+
|
|
143
|
+
| Prop | Type | Default | Description |
|
|
144
|
+
|------|------|---------|-------------|
|
|
145
|
+
| `readOnly` | `boolean` | `false` | Display-only mode (no interactions) |
|
|
146
|
+
| `disabled` | `boolean` | `false` | Fully disabled state |
|
|
147
|
+
| `disabledSlots` | `Schedule` | — | Slots that cannot be selected |
|
|
148
|
+
|
|
149
|
+
### Toolbar
|
|
150
|
+
|
|
151
|
+
| Prop | Type | Default | Description |
|
|
152
|
+
|------|------|---------|-------------|
|
|
153
|
+
| `presets` | `Preset[]` | 4 built-in | Preset buttons. Empty array hides the toolbar entries |
|
|
154
|
+
| `hideToolbar` | `boolean` | `false` | Hide the toolbar entirely |
|
|
155
|
+
|
|
156
|
+
### Styling
|
|
157
|
+
|
|
158
|
+
| Prop | Type | Default | Description |
|
|
159
|
+
|------|------|---------|-------------|
|
|
160
|
+
| `className` | `string` | — | Extra class on the outermost container |
|
|
161
|
+
|
|
162
|
+
## Localization Details
|
|
163
|
+
|
|
164
|
+
Each `locale` preset bundles week start, hour format, weekend colors, and translated text in one prop:
|
|
165
|
+
|
|
166
|
+
| `locale` | Week start | Hour format | Sat / Sun | `clear` |
|
|
167
|
+
|----------|-----------|-------------|-----------|---------|
|
|
168
|
+
| `"en"` | Mon | `14` | none | Clear |
|
|
169
|
+
| `"en-US"` | Sun | `2PM` | none | Clear |
|
|
170
|
+
| `"ko"` | Mon | `14` | blue / red | 초기화 |
|
|
171
|
+
| `"ja"` | Sun | `14` | blue / red | クリア |
|
|
172
|
+
| `"zh-CN"` | Mon | `14` | red / red | 清除 |
|
|
173
|
+
| `"zh-TW"` | Mon | `14` | red / red | 清除 |
|
|
174
|
+
|
|
175
|
+
Preset button labels (Weekday Day / Weekday Night / etc.) are translated per locale as well.
|
|
176
|
+
|
|
177
|
+
### Override priority
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
explicit prop (dayLabels / formatHour / visibleDays / presets)
|
|
181
|
+
> messages / weekStartsOn / weekendHighlight props
|
|
182
|
+
> LOCALE_PRESETS[locale]
|
|
183
|
+
> "en" fallback
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Serialization
|
|
187
|
+
|
|
188
|
+
The internal `Schedule` shape is optimized for rendering. For API transport and storage, convert it with one of the bundled helpers.
|
|
189
|
+
|
|
190
|
+
### `toRanges(schedule, options?)`
|
|
191
|
+
|
|
192
|
+
Compress consecutive hours into `[start, end)` ranges, keyed by ISO 8601 day-of-week (1=Mon … 7=Sun).
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
import { toRanges } from "react-schedule-picker";
|
|
196
|
+
|
|
197
|
+
toRanges({ mon: [9, 10, 11, 14, 15] }, { timezone: "Asia/Seoul" });
|
|
198
|
+
// {
|
|
199
|
+
// version: 1,
|
|
200
|
+
// timezone: "Asia/Seoul",
|
|
201
|
+
// ranges: [
|
|
202
|
+
// { day: 1, start: "09:00", end: "12:00" },
|
|
203
|
+
// { day: 1, start: "14:00", end: "16:00" },
|
|
204
|
+
// ],
|
|
205
|
+
// }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### `fromRanges(payload)`
|
|
209
|
+
|
|
210
|
+
Inverse of `toRanges`. Accepts only hour-aligned input.
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
import { fromRanges } from "react-schedule-picker";
|
|
214
|
+
|
|
215
|
+
fromRanges({
|
|
216
|
+
version: 1,
|
|
217
|
+
ranges: [{ day: 1, start: "09:00", end: "12:00" }],
|
|
218
|
+
});
|
|
219
|
+
// { mon: [9, 10, 11] }
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### `toISO(schedule, options?)`
|
|
223
|
+
|
|
224
|
+
Same data as `toRanges`, but with iCalendar-style field names (`startTime` / `endTime`).
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { toISO } from "react-schedule-picker";
|
|
228
|
+
|
|
229
|
+
toISO({ mon: [9, 10, 11] }, { timezone: "Asia/Seoul" });
|
|
230
|
+
// {
|
|
231
|
+
// version: 1,
|
|
232
|
+
// timezone: "Asia/Seoul",
|
|
233
|
+
// availability: [
|
|
234
|
+
// { day: 1, startTime: "09:00", endTime: "12:00" },
|
|
235
|
+
// ],
|
|
236
|
+
// }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Notes
|
|
240
|
+
|
|
241
|
+
- 1-hour granularity only. Sub-hour (15/30 min) is not supported.
|
|
242
|
+
- Ranges use half-open intervals: `end` is exclusive. `end: "24:00"` means up to midnight.
|
|
243
|
+
- Day keys in the raw `Schedule` are strings (`"mon"`…`"sun"`). ISO numeric keys appear only in serialized output.
|
|
244
|
+
|
|
245
|
+
## Theming
|
|
246
|
+
|
|
247
|
+
All colors and sizes are CSS custom properties on `.rsp-container`. Override what you need:
|
|
248
|
+
|
|
249
|
+
```css
|
|
250
|
+
.rsp-container {
|
|
251
|
+
--rsp-color-selected: #34d399;
|
|
252
|
+
--rsp-color-border: #d4d4d8;
|
|
253
|
+
--rsp-cell-size: 40px;
|
|
254
|
+
--rsp-border-radius: 12px;
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
See [`src/variables.css`](./src/variables.css) for the full list.
|
|
259
|
+
|
|
260
|
+
## Requirements
|
|
261
|
+
|
|
262
|
+
- React 18+
|
|
263
|
+
- Modern browsers (last 2 versions of Chrome, Safari, Firefox, Edge)
|
|
264
|
+
- TypeScript 4.7+ (optional)
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
[MIT](./LICENSE) © [innerbloo](https://github.com/innerbloo)
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
/* src/variables.css */
|
|
2
|
+
:root {
|
|
3
|
+
--rsp-color-primary: #2d6af6;
|
|
4
|
+
--rsp-color-primary-light: #ecf1ff;
|
|
5
|
+
--rsp-color-selected: #bbcaff;
|
|
6
|
+
--rsp-color-selected-readonly: #d4d4d8;
|
|
7
|
+
--rsp-color-border: #e4e4e7;
|
|
8
|
+
--rsp-color-bg: #ffffff;
|
|
9
|
+
--rsp-color-bg-header: #f4f4f5;
|
|
10
|
+
--rsp-color-bg-label: #fafafa;
|
|
11
|
+
--rsp-color-bg-hover: #efeff1;
|
|
12
|
+
--rsp-color-text: #2c2c31;
|
|
13
|
+
--rsp-color-text-sub: #71717a;
|
|
14
|
+
--rsp-color-text-header: #1c1c20;
|
|
15
|
+
--rsp-color-saturday: var(--rsp-color-primary);
|
|
16
|
+
--rsp-color-sunday: #f04646;
|
|
17
|
+
--rsp-cell-size: 36px;
|
|
18
|
+
--rsp-day-col-width: 48px;
|
|
19
|
+
--rsp-border-radius: 8px;
|
|
20
|
+
--rsp-font-family: inherit;
|
|
21
|
+
--rsp-font-size-sm: 12px;
|
|
22
|
+
--rsp-font-size-md: 14px;
|
|
23
|
+
--rsp-preset-bg: var(--rsp-color-bg);
|
|
24
|
+
--rsp-preset-bg-hover: var(--rsp-color-bg-hover);
|
|
25
|
+
--rsp-preset-border: var(--rsp-color-border);
|
|
26
|
+
--rsp-preset-text: var(--rsp-color-text);
|
|
27
|
+
--rsp-preset-radius: 9999px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* src/SchedulePicker.css */
|
|
31
|
+
.rsp-container {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
gap: 8px;
|
|
35
|
+
font-family: var(--rsp-font-family);
|
|
36
|
+
}
|
|
37
|
+
.rsp-toolbar {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
gap: 8px;
|
|
41
|
+
flex-wrap: wrap;
|
|
42
|
+
}
|
|
43
|
+
.rsp-toolbar-clear {
|
|
44
|
+
margin-left: auto;
|
|
45
|
+
}
|
|
46
|
+
.rsp-preset-button {
|
|
47
|
+
font-size: var(--rsp-font-size-md);
|
|
48
|
+
line-height: 1.6;
|
|
49
|
+
padding: 2px 8px;
|
|
50
|
+
border: 1px solid var(--rsp-preset-border);
|
|
51
|
+
border-radius: var(--rsp-preset-radius);
|
|
52
|
+
background-color: var(--rsp-preset-bg);
|
|
53
|
+
color: var(--rsp-preset-text);
|
|
54
|
+
cursor: pointer;
|
|
55
|
+
white-space: nowrap;
|
|
56
|
+
}
|
|
57
|
+
.rsp-preset-button:hover {
|
|
58
|
+
background-color: var(--rsp-preset-bg-hover);
|
|
59
|
+
}
|
|
60
|
+
.rsp-table-wrapper {
|
|
61
|
+
overflow-x: auto;
|
|
62
|
+
-webkit-overflow-scrolling: touch;
|
|
63
|
+
user-select: none;
|
|
64
|
+
-webkit-user-select: none;
|
|
65
|
+
}
|
|
66
|
+
.rsp-table {
|
|
67
|
+
border-collapse: separate;
|
|
68
|
+
border-spacing: 0;
|
|
69
|
+
border: 1px solid var(--rsp-color-border);
|
|
70
|
+
border-radius: var(--rsp-border-radius);
|
|
71
|
+
width: 100%;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
background-color: var(--rsp-color-bg);
|
|
74
|
+
}
|
|
75
|
+
.rsp-day-col {
|
|
76
|
+
width: var(--rsp-day-col-width);
|
|
77
|
+
}
|
|
78
|
+
.rsp-header-row {
|
|
79
|
+
background-color: var(--rsp-color-bg-header);
|
|
80
|
+
}
|
|
81
|
+
.rsp-corner-cell {
|
|
82
|
+
background-color: var(--rsp-color-bg-header);
|
|
83
|
+
}
|
|
84
|
+
.rsp-corner-cell--clickable {
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
}
|
|
87
|
+
.rsp-corner-cell--clickable:hover {
|
|
88
|
+
background-color: var(--rsp-color-bg-hover);
|
|
89
|
+
}
|
|
90
|
+
.rsp-header-cell {
|
|
91
|
+
font-size: var(--rsp-font-size-sm);
|
|
92
|
+
line-height: 1.6;
|
|
93
|
+
font-weight: 400;
|
|
94
|
+
color: var(--rsp-color-text-header);
|
|
95
|
+
text-align: center;
|
|
96
|
+
padding: 6px 0;
|
|
97
|
+
cursor: pointer;
|
|
98
|
+
touch-action: none;
|
|
99
|
+
}
|
|
100
|
+
.rsp-header-cell span {
|
|
101
|
+
display: inline-block;
|
|
102
|
+
}
|
|
103
|
+
.rsp-header-cell:hover {
|
|
104
|
+
background-color: var(--rsp-color-bg-hover);
|
|
105
|
+
}
|
|
106
|
+
.rsp-day-row {
|
|
107
|
+
}
|
|
108
|
+
.rsp-day-label {
|
|
109
|
+
font-size: var(--rsp-font-size-sm);
|
|
110
|
+
line-height: 1;
|
|
111
|
+
font-weight: 400;
|
|
112
|
+
color: var(--rsp-color-text-header);
|
|
113
|
+
text-align: center;
|
|
114
|
+
height: var(--rsp-cell-size);
|
|
115
|
+
padding: 0;
|
|
116
|
+
background-color: var(--rsp-color-bg-label);
|
|
117
|
+
border-top: 1px solid var(--rsp-color-border);
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
touch-action: none;
|
|
120
|
+
}
|
|
121
|
+
.rsp-day-label:hover {
|
|
122
|
+
background-color: var(--rsp-color-bg-hover);
|
|
123
|
+
}
|
|
124
|
+
.rsp-cell {
|
|
125
|
+
padding: 0;
|
|
126
|
+
width: var(--rsp-cell-size);
|
|
127
|
+
height: var(--rsp-cell-size);
|
|
128
|
+
border-left: 1px solid var(--rsp-color-border);
|
|
129
|
+
border-top: 1px solid var(--rsp-color-border);
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
touch-action: none;
|
|
132
|
+
-webkit-touch-callout: none;
|
|
133
|
+
}
|
|
134
|
+
.rsp-cell:hover {
|
|
135
|
+
background-color: var(--rsp-color-bg-hover);
|
|
136
|
+
}
|
|
137
|
+
.rsp-cell--highlighted {
|
|
138
|
+
background-color: var(--rsp-color-bg-hover);
|
|
139
|
+
}
|
|
140
|
+
.rsp-cell--selected {
|
|
141
|
+
background-color: var(--rsp-color-selected);
|
|
142
|
+
}
|
|
143
|
+
.rsp-cell--selected:hover {
|
|
144
|
+
background-color: var(--rsp-color-selected);
|
|
145
|
+
filter: brightness(1.1);
|
|
146
|
+
}
|
|
147
|
+
.rsp-cell--disabled {
|
|
148
|
+
background-color: var(--rsp-color-bg-header);
|
|
149
|
+
cursor: not-allowed;
|
|
150
|
+
background-image:
|
|
151
|
+
repeating-linear-gradient(
|
|
152
|
+
45deg,
|
|
153
|
+
transparent,
|
|
154
|
+
transparent 3px,
|
|
155
|
+
var(--rsp-color-border) 3px,
|
|
156
|
+
var(--rsp-color-border) 4px);
|
|
157
|
+
}
|
|
158
|
+
.rsp-cell--disabled:hover {
|
|
159
|
+
background-color: var(--rsp-color-bg-header);
|
|
160
|
+
background-image:
|
|
161
|
+
repeating-linear-gradient(
|
|
162
|
+
45deg,
|
|
163
|
+
transparent,
|
|
164
|
+
transparent 3px,
|
|
165
|
+
var(--rsp-color-border) 3px,
|
|
166
|
+
var(--rsp-color-border) 4px);
|
|
167
|
+
}
|
|
168
|
+
.rsp-cell--readonly {
|
|
169
|
+
cursor: default;
|
|
170
|
+
}
|
|
171
|
+
.rsp-cell--readonly:hover {
|
|
172
|
+
background-color: transparent;
|
|
173
|
+
}
|
|
174
|
+
.rsp-cell--readonly.rsp-cell--selected {
|
|
175
|
+
background-color: var(--rsp-color-selected-readonly);
|
|
176
|
+
}
|
|
177
|
+
.rsp-cell--readonly.rsp-cell--selected:hover {
|
|
178
|
+
background-color: var(--rsp-color-selected-readonly);
|
|
179
|
+
}
|
|
180
|
+
.rsp-day-label--readonly,
|
|
181
|
+
.rsp-header-cell--readonly {
|
|
182
|
+
cursor: default;
|
|
183
|
+
}
|
|
184
|
+
.rsp-day-label--readonly:hover {
|
|
185
|
+
background-color: var(--rsp-color-bg-label);
|
|
186
|
+
}
|
|
187
|
+
.rsp-header-cell--readonly:hover {
|
|
188
|
+
background-color: transparent;
|
|
189
|
+
}
|
|
190
|
+
.rsp-container--disabled {
|
|
191
|
+
pointer-events: none;
|
|
192
|
+
}
|
|
193
|
+
.rsp-container--disabled .rsp-cell {
|
|
194
|
+
background-color: var(--rsp-color-bg-header);
|
|
195
|
+
}
|
|
196
|
+
.rsp-container--disabled .rsp-cell--selected {
|
|
197
|
+
background-color: var(--rsp-color-selected-readonly);
|
|
198
|
+
}
|
|
199
|
+
.rsp-container--disabled .rsp-header-cell,
|
|
200
|
+
.rsp-container--disabled .rsp-day-label,
|
|
201
|
+
.rsp-container--disabled .rsp-hour-label {
|
|
202
|
+
color: var(--rsp-color-text-sub);
|
|
203
|
+
}
|
|
204
|
+
.rsp-container--disabled .rsp-preset-button {
|
|
205
|
+
color: var(--rsp-color-text-sub);
|
|
206
|
+
border-color: var(--rsp-color-border);
|
|
207
|
+
}
|
|
208
|
+
.rsp-hour-col {
|
|
209
|
+
width: var(--rsp-day-col-width);
|
|
210
|
+
}
|
|
211
|
+
.rsp-hour-label {
|
|
212
|
+
font-size: var(--rsp-font-size-sm);
|
|
213
|
+
line-height: 1;
|
|
214
|
+
font-weight: 400;
|
|
215
|
+
color: var(--rsp-color-text-header);
|
|
216
|
+
text-align: center;
|
|
217
|
+
height: var(--rsp-cell-size);
|
|
218
|
+
padding: 0;
|
|
219
|
+
background-color: var(--rsp-color-bg-label);
|
|
220
|
+
border-top: 1px solid var(--rsp-color-border);
|
|
221
|
+
cursor: pointer;
|
|
222
|
+
touch-action: none;
|
|
223
|
+
}
|
|
224
|
+
.rsp-hour-label:hover {
|
|
225
|
+
background-color: var(--rsp-color-bg-hover);
|
|
226
|
+
}
|
|
227
|
+
.rsp-hour-label--readonly {
|
|
228
|
+
cursor: default;
|
|
229
|
+
}
|
|
230
|
+
.rsp-hour-label--readonly:hover {
|
|
231
|
+
background-color: var(--rsp-color-bg-label);
|
|
232
|
+
}
|
|
233
|
+
.rsp-header-cell--day {
|
|
234
|
+
text-align: center;
|
|
235
|
+
}
|
|
236
|
+
.rsp-header-cell--day span {
|
|
237
|
+
transform: none;
|
|
238
|
+
}
|
|
239
|
+
@media (max-width: 639px) {
|
|
240
|
+
.rsp-day-label {
|
|
241
|
+
width: 36px;
|
|
242
|
+
font-size: var(--rsp-font-size-sm);
|
|
243
|
+
padding: 6px 0;
|
|
244
|
+
}
|
|
245
|
+
.rsp-day-col {
|
|
246
|
+
width: 36px;
|
|
247
|
+
}
|
|
248
|
+
.rsp-cell {
|
|
249
|
+
width: 30px;
|
|
250
|
+
height: 30px;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/variables.css","../src/SchedulePicker.css"],"sourcesContent":[":root {\n /* 색상 */\n --rsp-color-primary: #2d6af6;\n --rsp-color-primary-light: #ecf1ff;\n --rsp-color-selected: #bbcaff;\n --rsp-color-selected-readonly: #d4d4d8;\n --rsp-color-border: #e4e4e7;\n --rsp-color-bg: #ffffff;\n --rsp-color-bg-header: #f4f4f5;\n --rsp-color-bg-label: #fafafa;\n --rsp-color-bg-hover: #efeff1;\n --rsp-color-text: #2c2c31;\n --rsp-color-text-sub: #71717a;\n --rsp-color-text-header: #1c1c20;\n --rsp-color-saturday: var(--rsp-color-primary);\n --rsp-color-sunday: #f04646;\n\n /* 크기 */\n --rsp-cell-size: 36px;\n --rsp-day-col-width: 48px;\n --rsp-border-radius: 8px;\n\n /* 폰트 */\n --rsp-font-family: inherit;\n --rsp-font-size-sm: 12px;\n --rsp-font-size-md: 14px;\n\n /* 프리셋 버튼 */\n --rsp-preset-bg: var(--rsp-color-bg);\n --rsp-preset-bg-hover: var(--rsp-color-bg-hover);\n --rsp-preset-border: var(--rsp-color-border);\n --rsp-preset-text: var(--rsp-color-text);\n --rsp-preset-radius: 9999px;\n}\n\n","@import \"./variables.css\";\n\n/* 컨테이너 */\n.rsp-container {\n display: flex;\n flex-direction: column;\n gap: 8px;\n font-family: var(--rsp-font-family);\n}\n\n/* 프리셋 툴바 */\n.rsp-toolbar {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n\n.rsp-toolbar-clear {\n margin-left: auto;\n}\n\n.rsp-preset-button {\n font-size: var(--rsp-font-size-md);\n line-height: 1.6;\n padding: 2px 8px;\n border: 1px solid var(--rsp-preset-border);\n border-radius: var(--rsp-preset-radius);\n background-color: var(--rsp-preset-bg);\n color: var(--rsp-preset-text);\n cursor: pointer;\n white-space: nowrap;\n}\n\n.rsp-preset-button:hover {\n background-color: var(--rsp-preset-bg-hover);\n}\n\n/* 테이블 래퍼 — 가로 스크롤 */\n.rsp-table-wrapper {\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n user-select: none;\n -webkit-user-select: none;\n}\n\n/* 테이블 */\n.rsp-table {\n border-collapse: separate;\n border-spacing: 0;\n border: 1px solid var(--rsp-color-border);\n border-radius: var(--rsp-border-radius);\n width: 100%;\n overflow: hidden;\n background-color: var(--rsp-color-bg);\n}\n\n/* 요일 라벨 컬럼 폭 */\n.rsp-day-col {\n width: var(--rsp-day-col-width);\n}\n\n/* 헤더 행 */\n.rsp-header-row {\n background-color: var(--rsp-color-bg-header);\n}\n\n/* 좌상단 코너 셀 */\n.rsp-corner-cell {\n background-color: var(--rsp-color-bg-header);\n}\n\n.rsp-corner-cell--clickable {\n cursor: pointer;\n}\n\n.rsp-corner-cell--clickable:hover {\n background-color: var(--rsp-color-bg-hover);\n}\n\n/* 시간 헤더 셀 */\n.rsp-header-cell {\n font-size: var(--rsp-font-size-sm);\n line-height: 1.6;\n font-weight: 400;\n color: var(--rsp-color-text-header);\n text-align: center;\n padding: 6px 0;\n cursor: pointer;\n touch-action: none;\n}\n\n.rsp-header-cell span {\n display: inline-block;\n}\n\n.rsp-header-cell:hover {\n background-color: var(--rsp-color-bg-hover);\n}\n\n/* 요일 행 */\n.rsp-day-row {\n}\n\n/* 요일 라벨 셀 */\n.rsp-day-label {\n font-size: var(--rsp-font-size-sm);\n line-height: 1;\n font-weight: 400;\n color: var(--rsp-color-text-header);\n text-align: center;\n height: var(--rsp-cell-size);\n padding: 0;\n background-color: var(--rsp-color-bg-label);\n border-top: 1px solid var(--rsp-color-border);\n cursor: pointer;\n touch-action: none;\n}\n\n.rsp-day-label:hover {\n background-color: var(--rsp-color-bg-hover);\n}\n\n/* 주말 강조 색상은 컴포넌트가 weekendHighlight prop/locale 기반 인라인 style로 주입합니다.\n .rsp-day-label--sat, .rsp-day-label--sun 클래스명은 사용자 커스텀 CSS 오버라이드를 위해 유지합니다. */\n\n/* 시간 셀 */\n.rsp-cell {\n padding: 0;\n width: var(--rsp-cell-size);\n height: var(--rsp-cell-size);\n border-left: 1px solid var(--rsp-color-border);\n border-top: 1px solid var(--rsp-color-border);\n cursor: pointer;\n touch-action: none;\n -webkit-touch-callout: none;\n}\n\n.rsp-cell:hover {\n background-color: var(--rsp-color-bg-hover);\n}\n\n.rsp-cell--highlighted {\n background-color: var(--rsp-color-bg-hover);\n}\n\n.rsp-cell--selected {\n background-color: var(--rsp-color-selected);\n}\n\n.rsp-cell--selected:hover {\n background-color: var(--rsp-color-selected);\n filter: brightness(1.1);\n}\n\n/* disabledSlots: 빗금 패턴 */\n.rsp-cell--disabled {\n background-color: var(--rsp-color-bg-header);\n cursor: not-allowed;\n background-image: repeating-linear-gradient(\n 45deg,\n transparent,\n transparent 3px,\n var(--rsp-color-border) 3px,\n var(--rsp-color-border) 4px\n );\n}\n\n.rsp-cell--disabled:hover {\n background-color: var(--rsp-color-bg-header);\n background-image: repeating-linear-gradient(\n 45deg,\n transparent,\n transparent 3px,\n var(--rsp-color-border) 3px,\n var(--rsp-color-border) 4px\n );\n}\n\n/* readOnly: 선택 셀 회색, 호버 없음 */\n.rsp-cell--readonly {\n cursor: default;\n}\n\n.rsp-cell--readonly:hover {\n background-color: transparent;\n}\n\n.rsp-cell--readonly.rsp-cell--selected {\n background-color: var(--rsp-color-selected-readonly);\n}\n\n.rsp-cell--readonly.rsp-cell--selected:hover {\n background-color: var(--rsp-color-selected-readonly);\n}\n\n.rsp-day-label--readonly,\n.rsp-header-cell--readonly {\n cursor: default;\n}\n\n.rsp-day-label--readonly:hover {\n background-color: var(--rsp-color-bg-label);\n}\n\n.rsp-header-cell--readonly:hover {\n background-color: transparent;\n}\n\n/* disabled: 전체 회색 배경 + 상호작용 불가 */\n.rsp-container--disabled {\n pointer-events: none;\n}\n\n.rsp-container--disabled .rsp-cell {\n background-color: var(--rsp-color-bg-header);\n}\n\n.rsp-container--disabled .rsp-cell--selected {\n background-color: var(--rsp-color-selected-readonly);\n}\n\n.rsp-container--disabled .rsp-header-cell,\n.rsp-container--disabled .rsp-day-label,\n.rsp-container--disabled .rsp-hour-label {\n color: var(--rsp-color-text-sub);\n}\n\n.rsp-container--disabled .rsp-preset-button {\n color: var(--rsp-color-text-sub);\n border-color: var(--rsp-color-border);\n}\n\n/* dayAxis=\"x\" 모드: 시간 라벨 컬럼 */\n.rsp-hour-col {\n width: var(--rsp-day-col-width);\n}\n\n.rsp-hour-label {\n font-size: var(--rsp-font-size-sm);\n line-height: 1;\n font-weight: 400;\n color: var(--rsp-color-text-header);\n text-align: center;\n height: var(--rsp-cell-size);\n padding: 0;\n background-color: var(--rsp-color-bg-label);\n border-top: 1px solid var(--rsp-color-border);\n cursor: pointer;\n touch-action: none;\n}\n\n.rsp-hour-label:hover {\n background-color: var(--rsp-color-bg-hover);\n}\n\n.rsp-hour-label--readonly {\n cursor: default;\n}\n\n.rsp-hour-label--readonly:hover {\n background-color: var(--rsp-color-bg-label);\n}\n\n/* dayAxis=\"x\" 모드: 요일 헤더 센터 정렬 */\n.rsp-header-cell--day {\n text-align: center;\n}\n\n.rsp-header-cell--day span {\n transform: none;\n}\n\n/* 모바일 최적화 (터치 타겟 권장 크기 ~30px+) */\n@media (max-width: 639px) {\n .rsp-day-label {\n width: 36px;\n font-size: var(--rsp-font-size-sm);\n padding: 6px 0;\n }\n\n .rsp-day-col {\n width: 36px;\n }\n\n .rsp-cell {\n width: 30px;\n height: 30px;\n }\n}\n"],"mappings":"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","names":[]}
|