@g4rcez/components 2.2.8 → 2.3.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/dist/components/core/button.d.ts.map +1 -1
- package/dist/components/core/polymorph.d.ts.map +1 -1
- package/dist/components/core/slot.d.ts +1 -1
- package/dist/components/core/slot.d.ts.map +1 -1
- package/dist/components/core/slot.jsx +28 -35
- package/dist/components/core/tag.jsx +1 -1
- package/dist/components/core/typography.d.ts.map +1 -1
- package/dist/components/core/typography.jsx +16 -20
- package/dist/components/display/alert.d.ts.map +1 -1
- package/dist/components/display/alert.jsx +22 -24
- package/dist/components/display/calendar.d.ts.map +1 -1
- package/dist/components/display/calendar.jsx +5 -7
- package/dist/components/display/card.d.ts.map +1 -1
- package/dist/components/display/card.jsx +5 -5
- package/dist/components/display/empty.jsx +1 -1
- package/dist/components/display/notifications.d.ts.map +1 -1
- package/dist/components/display/notifications.jsx +35 -35
- package/dist/components/display/progress.d.ts.map +1 -1
- package/dist/components/display/progress.jsx +6 -8
- package/dist/components/display/shortcut.jsx +1 -1
- package/dist/components/display/skeleton.d.ts.map +1 -1
- package/dist/components/display/skeleton.jsx +3 -5
- package/dist/components/display/step.d.ts.map +1 -1
- package/dist/components/display/step.jsx +27 -27
- package/dist/components/display/tabs.d.ts.map +1 -1
- package/dist/components/display/tabs.jsx +5 -7
- package/dist/components/floating/command-palette.d.ts.map +1 -1
- package/dist/components/floating/command-palette.jsx +40 -40
- package/dist/components/floating/dropdown.d.ts.map +1 -1
- package/dist/components/floating/dropdown.jsx +15 -15
- package/dist/components/floating/modal.d.ts.map +1 -1
- package/dist/components/floating/modal.jsx +73 -67
- package/dist/components/floating/tooltip.d.ts.map +1 -1
- package/dist/components/floating/tooltip.jsx +2 -8
- package/dist/components/floating/wizard.d.ts +1 -1
- package/dist/components/floating/wizard.d.ts.map +1 -1
- package/dist/components/floating/wizard.jsx +50 -53
- package/dist/components/form/autocomplete.d.ts.map +1 -1
- package/dist/components/form/autocomplete.jsx +38 -35
- package/dist/components/form/checkbox.jsx +2 -2
- package/dist/components/form/date-picker.d.ts.map +1 -1
- package/dist/components/form/date-picker.jsx +14 -14
- package/dist/components/form/file-upload.jsx +13 -13
- package/dist/components/form/free-text.d.ts.map +1 -1
- package/dist/components/form/free-text.jsx +2 -2
- package/dist/components/form/input-field.d.ts.map +1 -1
- package/dist/components/form/input-field.jsx +42 -41
- package/dist/components/form/multi-select.d.ts.map +1 -1
- package/dist/components/form/multi-select.jsx +56 -56
- package/dist/components/form/select.d.ts.map +1 -1
- package/dist/components/form/select.jsx +13 -13
- package/dist/components/form/slider.d.ts.map +1 -1
- package/dist/components/form/slider.jsx +10 -10
- package/dist/components/form/transfer-list.jsx +3 -3
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/page-calendar/calendar-header.d.ts +16 -0
- package/dist/components/page-calendar/calendar-header.d.ts.map +1 -0
- package/dist/components/page-calendar/calendar-header.jsx +81 -0
- package/dist/components/page-calendar/day-view.d.ts +12 -0
- package/dist/components/page-calendar/day-view.d.ts.map +1 -0
- package/dist/components/page-calendar/day-view.jsx +84 -0
- package/dist/components/page-calendar/event-pill.d.ts +9 -0
- package/dist/components/page-calendar/event-pill.d.ts.map +1 -0
- package/dist/components/page-calendar/event-pill.jsx +23 -0
- package/dist/components/page-calendar/index.d.ts +4 -0
- package/dist/components/page-calendar/index.d.ts.map +1 -0
- package/dist/components/page-calendar/index.js +2 -0
- package/dist/components/page-calendar/month-view.d.ts +11 -0
- package/dist/components/page-calendar/month-view.d.ts.map +1 -0
- package/dist/components/page-calendar/month-view.jsx +47 -0
- package/dist/components/page-calendar/page-calendar.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.jsx +39 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.types.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.types.js +1 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts +18 -0
- package/dist/components/page-calendar/page-calendar.utils.d.ts.map +1 -0
- package/dist/components/page-calendar/page-calendar.utils.js +71 -0
- package/dist/components/page-calendar/week-view.d.ts +11 -0
- package/dist/components/page-calendar/week-view.d.ts.map +1 -0
- package/dist/components/page-calendar/week-view.jsx +61 -0
- package/dist/components/table/filter.jsx +4 -4
- package/dist/components/table/index.d.ts.map +1 -1
- package/dist/components/table/index.jsx +10 -10
- package/dist/components/table/inner-table.d.ts.map +1 -1
- package/dist/components/table/inner-table.jsx +18 -18
- package/dist/components/table/metadata.d.ts.map +1 -1
- package/dist/components/table/metadata.jsx +29 -30
- package/dist/components/table/pagination.jsx +1 -1
- package/dist/components/table/row.d.ts.map +1 -1
- package/dist/components/table/row.jsx +17 -17
- package/dist/components/table/sort.jsx +1 -1
- package/dist/components/table/table-lib.d.ts.map +1 -1
- package/dist/components/table/table-lib.js +1 -2
- package/dist/components/table/thead.d.ts.map +1 -1
- package/dist/components/table/thead.jsx +5 -5
- package/dist/config/context.d.ts.map +1 -1
- package/dist/config/default-translations.d.ts +10 -0
- package/dist/config/default-translations.d.ts.map +1 -1
- package/dist/config/default-translations.jsx +11 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/hooks/use-components-provider.d.ts.map +1 -1
- package/dist/hooks/use-components-provider.jsx +2 -2
- package/dist/hooks/use-form.d.ts.map +1 -1
- package/dist/hooks/use-input-id.d.ts.map +1 -1
- package/dist/hooks/use-is-coarse-device.js +1 -1
- package/dist/hooks/use-preferences.d.ts.map +1 -1
- package/dist/hooks/use-resize-observer.d.ts.map +1 -1
- package/dist/hooks/use-translations.d.ts +10 -0
- package/dist/hooks/use-translations.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10121 -9704
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +14 -14
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/dom.d.ts.map +1 -1
- package/dist/lib/fns.d.ts.map +1 -1
- package/dist/lib/fns.js +2 -2
- package/dist/preset/src/styles/theme.types.d.ts.map +1 -1
- package/dist/styles/theme.types.d.ts.map +1 -1
- package/package.json +289 -289
|
@@ -24,9 +24,9 @@ const transitionStyles = {
|
|
|
24
24
|
};
|
|
25
25
|
const emptyRef = [];
|
|
26
26
|
const List = forwardRef(function VirtualList(props, ref) {
|
|
27
|
-
return (<motion.ul {...props} role="listbox" ref={ref} className="w-full rounded-b-lg border-b last:border-transparent
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
return (<motion.ul {...props} role="listbox" ref={ref} className="w-full rounded-b-lg border-b border-tooltip-border last:border-transparent">
|
|
28
|
+
<AnimatePresence>{props.children}</AnimatePresence>
|
|
29
|
+
</motion.ul>);
|
|
30
30
|
});
|
|
31
31
|
const Item = forwardRef(function VirtualItem({ item, context, ...props }, ref) {
|
|
32
32
|
return <motion.li {...props} ref={ref} className="last:rounded-t-lg"/>;
|
|
@@ -50,10 +50,10 @@ const OverflowControl = (props) => {
|
|
|
50
50
|
return setNormalView(true);
|
|
51
51
|
}, [countable]);
|
|
52
52
|
return (<span ref={ref} className="flex flex-nowrap gap-x-2">
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
{!normalView ? (props.children) : (<Tag size="small" data-multicounter="true">
|
|
54
|
+
{countable} {translate.multiSelectSelectedLabel}
|
|
55
|
+
</Tag>)}
|
|
56
|
+
</span>);
|
|
57
57
|
};
|
|
58
58
|
export const MultiSelect = forwardRef(({ left, error, right, options, container, rightLabel, interactive, emptyMessage, optionalText, selectedLabel, labelClassName, feedback = null, hideLeft = false, required = false, dynamicOption = false, onChangeOptions, ...props }, externalRef) => {
|
|
59
59
|
const map = useMemo(() => new Dict(options.map((x) => [x.value, x])), [options]);
|
|
@@ -208,38 +208,38 @@ export const MultiSelect = forwardRef(({ left, error, right, options, container,
|
|
|
208
208
|
e.stopPropagation();
|
|
209
209
|
onSelect(x, i);
|
|
210
210
|
}}>
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
<XIcon size={14}/>
|
|
212
|
+
</button>}>
|
|
213
|
+
{x.label ?? x.value}
|
|
214
|
+
</Tag>));
|
|
215
215
|
const scrollableContainerStyle = { height: isEmpty ? "0" : value.size === 0 ? h - 49 : h - 86 };
|
|
216
|
-
return (<InputField {...props} left={left} error={error} ref={fieldset} form={props.form} name={props.name} feedback={feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} rightLabel={rightLabel} interactive={interactive} id={props.name || props.id} optionalText={optionalText} componentName="autocomplete" labelClassName={labelClassName} placeholder={props.placeholder} right={<span className="flex gap-0.5
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
216
|
+
return (<InputField {...props} left={left} error={error} ref={fieldset} form={props.form} name={props.name} feedback={feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} rightLabel={rightLabel} interactive={interactive} id={props.name || props.id} optionalText={optionalText} componentName="autocomplete" labelClassName={labelClassName} placeholder={props.placeholder} right={<span className="flex items-center gap-0.5">
|
|
217
|
+
{right}
|
|
218
|
+
<button type="button" className="transition-colors link:text-primary" onClick={onCaretDownClick}>
|
|
219
|
+
<ChevronDown size={20}/>
|
|
220
|
+
<span className="sr-only">{translation.inputCaretDown}</span>
|
|
221
|
+
</button>
|
|
222
|
+
{value ? (<button type="button" onClick={onClose} className="transition-colors link:text-danger">
|
|
223
|
+
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
224
|
+
<path d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z" fill="currentColor" fillRule="evenodd" clipRule="evenodd"/>
|
|
225
|
+
</svg>
|
|
226
|
+
</button>) : null}
|
|
227
|
+
</span>}>
|
|
228
|
+
<ul {...getReferenceProps({
|
|
229
229
|
...props,
|
|
230
230
|
onFocus,
|
|
231
231
|
id: `${id}-shadow`,
|
|
232
232
|
name: `${id}-shadow`,
|
|
233
233
|
ref: refs.setReference,
|
|
234
|
-
})} tabIndex={0} role="button" data-name={id} data-target={id} data-shadow="true" data-error={!!error} aria-autocomplete="list" data-value={values.join(",")} className={css("input
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
234
|
+
})} tabIndex={0} role="button" data-name={id} data-target={id} data-shadow="true" data-error={!!error} aria-autocomplete="list" data-value={values.join(",")} className={css("input placeholder-input-mask group h-input-height w-full text-base", "rounded-md bg-transparent px-input-x py-input-y text-foreground", "outline-none transition-colors focus:ring-2 focus:ring-inset focus:ring-primary", "group-error:text-danger group-error:placeholder-input-mask-error", "group-focus-within:border-primary group-hover:border-primary", "flex flex-row items-center gap-2 whitespace-nowrap text-left", "max-w-full overflow-x-auto truncate overflow-ellipsis", props.className)}>
|
|
235
|
+
{values.length > 0 ? null : <li className="text-input-placeholder">{props.placeholder}</li>}
|
|
236
|
+
<OverflowControl label={selectedLabel}>{tags}</OverflowControl>
|
|
237
|
+
</ul>
|
|
238
|
+
<input id={id} name={id} type="hidden" data-origin={id} ref={externalRef} required={required} defaultValue={props.value || values || undefined}/>
|
|
239
|
+
<FloatingPortal preserveTabOrder>
|
|
240
|
+
{open ? (<FloatingOverlay lockScroll>
|
|
241
|
+
<FloatingFocusManager modal guards returnFocus={false} context={context} initialFocus={-1} visuallyHiddenDismiss>
|
|
242
|
+
<div {...getFloatingProps({
|
|
243
243
|
ref: refs.setFloating,
|
|
244
244
|
style: {
|
|
245
245
|
...transitions.styles,
|
|
@@ -248,8 +248,8 @@ export const MultiSelect = forwardRef(({ left, error, right, options, container,
|
|
|
248
248
|
left: x,
|
|
249
249
|
height: h - (values.length === 0 ? 65 : 30),
|
|
250
250
|
},
|
|
251
|
-
})} data-floating="true" className="
|
|
252
|
-
|
|
251
|
+
})} data-floating="true" className="shadow-floating isolate z-floating m-0 max-h-96 w-full origin-[top_center] list-none overscroll-contain rounded-b-lg rounded-t-lg border border-floating-border bg-floating-background p-0 text-foreground">
|
|
252
|
+
<input autoFocus value={shadow} onChange={onChange} title={props.title} placeholder={translation.multiSelectInnerPlaceholder} className="input placeholder-input-mask group mb-1 h-10 w-full flex-1 rounded border-b border-input-border bg-transparent px-input-x py-input-y outline-none transition-colors focus:ring-2 focus:ring-inset focus:ring-primary" onKeyDown={(event) => {
|
|
253
253
|
if (event.key === "ArrowDown") {
|
|
254
254
|
let next = index + 1;
|
|
255
255
|
if (next > displayList.length - 1)
|
|
@@ -279,12 +279,12 @@ export const MultiSelect = forwardRef(({ left, error, right, options, container,
|
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
}}/>
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
282
|
+
{isEmpty ? (<li role="option" className="w-full border-b border-tooltip-border last:border-transparent">
|
|
283
|
+
<span className="flex w-full justify-between p-2 text-left text-disabled">
|
|
284
|
+
{emptyMessage || translation.autocompleteEmpty}
|
|
285
|
+
</span>
|
|
286
|
+
</li>) : null}
|
|
287
|
+
{isEmpty ? null : (<motion.div initial={false} data-floating="true" ref={removeScrollRef} animate={{ height: isEmpty ? "auto" : h }} style={scrollableContainerStyle} className="max-h-72 w-full overscroll-contain" onAnimationComplete={() => {
|
|
288
288
|
if (!open)
|
|
289
289
|
return setH(0);
|
|
290
290
|
const ul = refs.floating.current;
|
|
@@ -292,7 +292,7 @@ export const MultiSelect = forwardRef(({ left, error, right, options, container,
|
|
|
292
292
|
const sum = (li ? li.getBoundingClientRect().height : 40) * displayList.length;
|
|
293
293
|
return flushSync(() => setH(sum + 2));
|
|
294
294
|
}}>
|
|
295
|
-
|
|
295
|
+
<Virtuoso ref={virtuoso} hidden={isEmpty} data={displayList} components={components} style={scrollableContainerStyle} className="max-h-72 border-floating-border bg-floating-background p-0 text-foreground" itemContent={(i, option) => {
|
|
296
296
|
const Label = option.Render ?? Frag;
|
|
297
297
|
const active = value.has(option.value) || value.has(option.label ?? "");
|
|
298
298
|
const selected = index === i;
|
|
@@ -307,22 +307,22 @@ export const MultiSelect = forwardRef(({ left, error, right, options, container,
|
|
|
307
307
|
"aria-busy": option.disabled,
|
|
308
308
|
onClick: () => onSelect(option, i),
|
|
309
309
|
})} className={`flex w-full max-w-full cursor-pointer items-center justify-start p-2 text-left hover:bg-floating-hover focus:bg-floating-hover ${active || selected ? "bg-floating-hover text-floating-foreground" : ""}`}>
|
|
310
|
-
|
|
310
|
+
<Checkbox onChange={noop} checked={active} aria-checked={active} onClick={(e) => {
|
|
311
311
|
e.stopPropagation();
|
|
312
312
|
onSelect(option, i);
|
|
313
313
|
}}/>
|
|
314
|
-
|
|
315
|
-
|
|
314
|
+
<Label {...props} label={option.label} value={option.value} children={children}/>
|
|
315
|
+
</button>);
|
|
316
316
|
}}/>
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
317
|
+
</motion.div>)}
|
|
318
|
+
<div className="sticky bottom-0 flex w-full flex-nowrap items-center gap-2 overflow-x-auto rounded-b-lg bg-floating-background p-2">
|
|
319
|
+
{value.size === 0 ? (<Tag theme="muted" size="small">
|
|
320
|
+
{translation.autocompleteEmpty}
|
|
321
|
+
</Tag>) : (tags)}
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
</FloatingFocusManager>
|
|
325
|
+
</FloatingOverlay>) : null}
|
|
326
|
+
</FloatingPortal>
|
|
327
|
+
</InputField>);
|
|
328
328
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/form/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA6D,MAAM,OAAO,CAAC;AAGlF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAc,eAAe,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,MAAM,WAAW,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/form/select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA6D,MAAM,OAAO,CAAC;AAGlF,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAc,eAAe,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,MAAM,WAAW,GAAG,QAAQ,CAC9B,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAC9B;IACI,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAChD,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,QAAQ,CAC9B,eAAe,CAAC,QAAQ,CAAC,EACzB;IACI,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B,CACJ,CAAC;AAEF,eAAO,MAAM,MAAM,oGA2GlB,CAAC"}
|
|
@@ -26,17 +26,17 @@ export const Select = forwardRef(({ required = true, options, info, selectContai
|
|
|
26
26
|
}, []);
|
|
27
27
|
const onClickLabel = () => inputRef.current?.focus();
|
|
28
28
|
return (<InputField info={info} left={left} error={error} form={props.form} loading={loading} name={props.name} feedback={feedback} hideLeft={hideLeft} required={required} title={props.title} container={container} componentName="select" rightLabel={rightLabel} hiddenLabel={hiddenLabel} interactive={interactive} id={props.name || props.id} optionalText={optionalText} labelClassName={labelClassName} placeholder={props.placeholder} right={<label htmlFor={id}>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
{right}
|
|
30
|
+
<button onClick={onClickLabel} type="button" className="mt-2 transition-colors hover:text-primary">
|
|
31
|
+
<ChevronDownIcon size={20}/>
|
|
32
|
+
<span className="sr-only">{translation.inputCaretDown}</span>
|
|
33
|
+
</button>
|
|
34
|
+
</label>}>
|
|
35
|
+
<select {...props} id={id} name={id} required={required} ref={mergeRefs(ref, inputRef)} data-selected={!!props.value || false} title={typeof props.title === "string" ? props.title : undefined} className={css("input select group h-10 w-full flex-1 appearance-none rounded-md text-base", "bg-transparent px-2 py-1 text-foreground placeholder-input-placeholder", "outline-none transition-colors group-error:text-danger group-error:placeholder-input-mask-error", "data-[selected=false]:text-input-placeholder", props.className)}>
|
|
36
|
+
<option value="" disabled hidden>
|
|
37
|
+
{props.placeholder}
|
|
38
|
+
</option>
|
|
39
|
+
{options.map((option) => (<option {...option} value={option.value} children={option.label ?? option.value} key={`${id}-select-option-${option.value}`}/>))}
|
|
40
|
+
</select>
|
|
41
|
+
</InputField>);
|
|
42
42
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../../../src/components/form/slider.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAQvD,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG;
|
|
1
|
+
{"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../../../src/components/form/slider.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,IAAI,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAQvD,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAmCF,eAAO,MAAM,MAAM,GAAI,OAAO,WAAW,gCAgBxC,CAAC"}
|
|
@@ -25,9 +25,9 @@ const Thumb = (props) => {
|
|
|
25
25
|
observer.observe(html, { attributeFilter: ["aria-valuenow"] });
|
|
26
26
|
return () => observer.disconnect();
|
|
27
27
|
}, []);
|
|
28
|
-
return (<Tooltip title="" ref={ref} as={Base.Thumb} enabled={props.tooltip} className="
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
return (<Tooltip title="" ref={ref} as={Base.Thumb} enabled={props.tooltip} className="focus-within::scale-105 block size-5 cursor-grab rounded-full border-2 border-input-border bg-input-switch shadow-shadow-floating focus-within:border-primary focus-within:outline active:cursor-grabbing">
|
|
29
|
+
{float}
|
|
30
|
+
</Tooltip>);
|
|
31
31
|
};
|
|
32
32
|
export const Slider = (props) => {
|
|
33
33
|
const { tooltip, className, defaultValue, value, ...restProps } = props;
|
|
@@ -35,11 +35,11 @@ export const Slider = (props) => {
|
|
|
35
35
|
const array = defaultValue || value || [];
|
|
36
36
|
const locale = useLocale();
|
|
37
37
|
return (<Base.Root {...restProps} value={value} locale={locale} defaultValue={defaultValue}>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
<Base.Control className={css("relative flex h-5 w-full touch-none select-none items-center", className)}>
|
|
39
|
+
<Base.Track className="relative h-2 grow rounded-full bg-background">
|
|
40
|
+
<Base.Indicator className="absolute h-full rounded-full bg-primary"/>
|
|
41
|
+
</Base.Track>
|
|
42
|
+
{Array.isArray(array) ? array.map((_, i) => <Thumb tooltip={tooltip ?? false} key={`${id.current}-${i}`}/>) : null}
|
|
43
|
+
</Base.Control>
|
|
44
|
+
</Base.Root>);
|
|
45
45
|
};
|
|
@@ -8,7 +8,7 @@ import { Checkbox } from "../form/checkbox";
|
|
|
8
8
|
import { Input } from "./input";
|
|
9
9
|
const components = {
|
|
10
10
|
Item: forwardRef(function InnerList(props, ref) {
|
|
11
|
-
return <li {...props} ref={ref} className="flex items-center gap-1
|
|
11
|
+
return <li {...props} ref={ref} className="flex items-center justify-between gap-1"/>;
|
|
12
12
|
}),
|
|
13
13
|
List: forwardRef(function InnerList(props, ref) {
|
|
14
14
|
return <ul {...props} ref={ref} className="space-y-3"/>;
|
|
@@ -18,9 +18,9 @@ export const TransferList = (props) => {
|
|
|
18
18
|
const ref = useRef(null);
|
|
19
19
|
const h = useParentHeight(ref);
|
|
20
20
|
return (<div className="flex flex-row gap-4" ref={ref}>
|
|
21
|
-
<div className="
|
|
21
|
+
<div className="flex w-fit min-w-64 flex-col space-y-4 whitespace-nowrap rounded-lg border border-card-border py-8">
|
|
22
22
|
<header className="border-b border-card-border pb-2"></header>
|
|
23
|
-
<div className="
|
|
23
|
+
<div className="space-y-2 px-8">
|
|
24
24
|
<Input rightLabel="" title="Search" placeholder="Looking for..."/>
|
|
25
25
|
<Virtuoso height={h} useWindowScroll data={props.source} components={components} itemContent={(_, row) => (<Fragment>
|
|
26
26
|
<Checkbox>
|
|
@@ -39,6 +39,7 @@ export * from "./form/transfer-list";
|
|
|
39
39
|
export * from "./core/render-on-view";
|
|
40
40
|
export * from "./display/notifications";
|
|
41
41
|
export * from "./floating/command-palette";
|
|
42
|
+
export * from "./page-calendar";
|
|
42
43
|
export { formReset } from "./form/formReset";
|
|
43
44
|
export { createColumns, createOptionCols, type ColType, useTablePreferences, type TablePagination } from "./table/table-lib";
|
|
44
45
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,mBAAmB,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/components/index.js
CHANGED
|
@@ -39,5 +39,6 @@ export * from "./form/transfer-list";
|
|
|
39
39
|
export * from "./core/render-on-view";
|
|
40
40
|
export * from "./display/notifications";
|
|
41
41
|
export * from "./floating/command-palette";
|
|
42
|
+
export * from "./page-calendar";
|
|
42
43
|
export { formReset } from "./form/formReset";
|
|
43
44
|
export { createColumns, createOptionCols, useTablePreferences } from "./table/table-lib";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CalendarFilter, ViewMode } from "./page-calendar.types";
|
|
2
|
+
import type { SetState } from "../../types";
|
|
3
|
+
import { type ReactNode } from "react";
|
|
4
|
+
type CalendarHeaderProps = {
|
|
5
|
+
currentDate: Date;
|
|
6
|
+
currentView: ViewMode;
|
|
7
|
+
onAddEvent?: () => void;
|
|
8
|
+
filters: CalendarFilter[];
|
|
9
|
+
filterArea?: ReactNode;
|
|
10
|
+
setCurrentDate: SetState<Date>;
|
|
11
|
+
setCurrentView: SetState<ViewMode>;
|
|
12
|
+
onToggleFilter: (id: string) => void;
|
|
13
|
+
};
|
|
14
|
+
export declare function CalendarHeader({ currentDate, currentView, filters, filterArea, setCurrentDate, setCurrentView, onToggleFilter, onAddEvent, }: CalendarHeaderProps): import("react").JSX.Element;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=calendar-header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calendar-header.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/calendar-header.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEhD,KAAK,mBAAmB,GAAG;IACvB,WAAW,EAAE,IAAI,CAAC;IAClB,WAAW,EAAE,QAAQ,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,cAAc,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACnC,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,CAAC;AAEF,wBAAgB,cAAc,CAAC,EAC3B,WAAW,EACX,WAAW,EACX,OAAO,EACP,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,UAAU,GACb,EAAE,mBAAmB,+BAsGrB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Button } from "../core/button";
|
|
2
|
+
import { Tag } from "../core/tag";
|
|
3
|
+
import { useLocale } from "../../hooks/use-locale";
|
|
4
|
+
import { useTranslations } from "../../hooks/use-translations";
|
|
5
|
+
import { ChevronLeft, ChevronRight, PlusCircle, Calendar } from "lucide-react";
|
|
6
|
+
import { addDays, addMonths, addWeeks, isToday, subDays, subMonths, subWeeks } from "date-fns";
|
|
7
|
+
import { formatDay, formatMonthShort, formatMonthYear, getWeekNumber } from "./page-calendar.utils";
|
|
8
|
+
import { useMemo } from "react";
|
|
9
|
+
export function CalendarHeader({ currentDate, currentView, filters, filterArea, setCurrentDate, setCurrentView, onToggleFilter, onAddEvent, }) {
|
|
10
|
+
const locale = useLocale();
|
|
11
|
+
const t = useTranslations();
|
|
12
|
+
const isDateToday = isToday(currentDate);
|
|
13
|
+
const VIEWS = useMemo(() => [
|
|
14
|
+
{ value: "month", label: t.pageCalendarMonthView },
|
|
15
|
+
{ value: "week", label: t.pageCalendarWeekView },
|
|
16
|
+
{ value: "day", label: t.pageCalendarDayView },
|
|
17
|
+
], [t]);
|
|
18
|
+
const handlePrev = () => {
|
|
19
|
+
setCurrentDate((currentDate) => {
|
|
20
|
+
if (currentView === "month")
|
|
21
|
+
return subMonths(currentDate, 1);
|
|
22
|
+
if (currentView === "week")
|
|
23
|
+
return subWeeks(currentDate, 1);
|
|
24
|
+
return subDays(currentDate, 1);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const handleNext = () => {
|
|
28
|
+
setCurrentDate((currentDate) => {
|
|
29
|
+
if (currentView === "month")
|
|
30
|
+
return addMonths(currentDate, 1);
|
|
31
|
+
if (currentView === "week")
|
|
32
|
+
return addWeeks(currentDate, 1);
|
|
33
|
+
return addDays(currentDate, 1);
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const weekNum = getWeekNumber(currentDate);
|
|
37
|
+
return (<div className="flex flex-col gap-4">
|
|
38
|
+
<div className="flex items-center justify-between gap-4">
|
|
39
|
+
<div className="flex items-center gap-3">
|
|
40
|
+
<div className={`flex size-12 flex-col items-center justify-center overflow-hidden rounded-lg text-xs ${isDateToday ? "bg-primary text-primary-foreground" : "bg-card text-foreground"}`}>
|
|
41
|
+
<span className="font-light uppercase leading-none">{formatMonthShort(currentDate, locale)}</span>
|
|
42
|
+
<span className="text-xl font-medium leading-none">{formatDay(currentDate, locale)}</span>
|
|
43
|
+
</div>
|
|
44
|
+
<div>
|
|
45
|
+
<h1 className="text-xl font-bold leading-tight">{formatMonthYear(currentDate, locale)}</h1>
|
|
46
|
+
<span className="text-xs text-muted-foreground">{t.pageCalendarWeekLabel(weekNum)}</span>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<div className="flex items-center gap-2">
|
|
50
|
+
<div className="flex items-center gap-1">
|
|
51
|
+
<Button size="small" title={t.pageCalendarPrevious} theme="ghost-muted" onClick={handlePrev}>
|
|
52
|
+
<ChevronLeft size={16}/>
|
|
53
|
+
</Button>
|
|
54
|
+
<button onClick={() => setCurrentDate(new Date())} className="rounded-md px-3 py-1.5 text-sm transition-colors hover:bg-muted/50">
|
|
55
|
+
{t.pageCalendarToday}
|
|
56
|
+
</button>
|
|
57
|
+
<Button size="small" title={t.pageCalendarNext} theme="ghost-muted" onClick={handleNext}>
|
|
58
|
+
<ChevronRight size={16}/>
|
|
59
|
+
</Button>
|
|
60
|
+
</div>
|
|
61
|
+
<div className="flex rounded-md">
|
|
62
|
+
{VIEWS.map((v) => (<Button size="small" key={v.value} onClick={() => setCurrentView(v.value)} theme={currentView === v.value ? "primary" : "muted"} className="rounded-none first:rounded-l-button last:rounded-r-button">
|
|
63
|
+
{v.label}
|
|
64
|
+
</Button>))}
|
|
65
|
+
</div>
|
|
66
|
+
{onAddEvent && (<Button theme="primary" size="small" onClick={onAddEvent}>
|
|
67
|
+
<PlusCircle size={14}/>
|
|
68
|
+
{t.pageCalendarAddEvent}
|
|
69
|
+
</Button>)}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
{filterArea ??
|
|
73
|
+
(filters.length > 0 && (<div className="flex flex-wrap items-center gap-1.5">
|
|
74
|
+
<Calendar size={14} className="text-muted-foreground"/>
|
|
75
|
+
<span className="mr-1 text-xs text-muted-foreground">{t.pageCalendarFilter}</span>
|
|
76
|
+
{filters.map((filter) => (<Tag as="button" size="small" type="button" key={filter.id} theme={filter.theme} indicator={filter.enabled ? filter.theme : undefined} onClick={() => onToggleFilter(filter.id)}>
|
|
77
|
+
{filter.label}
|
|
78
|
+
</Tag>))}
|
|
79
|
+
</div>))}
|
|
80
|
+
</div>);
|
|
81
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CalendarEvent, CalendarEventBase } from "./page-calendar.types";
|
|
2
|
+
type DayViewProps<T extends CalendarEventBase> = {
|
|
3
|
+
currentDate: Date;
|
|
4
|
+
onDateChange: (date: Date) => void;
|
|
5
|
+
onSlotClick?: (date: Date) => void;
|
|
6
|
+
eventsByDate: Map<string, CalendarEvent<T>[]>;
|
|
7
|
+
onEventClick: (event: CalendarEvent<T>) => void;
|
|
8
|
+
renderEvent?: (event: CalendarEvent<T>) => React.ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export declare function DayView<T extends CalendarEventBase>({ currentDate, onSlotClick, renderEvent, eventsByDate, onDateChange, onEventClick, }: DayViewProps<T>): import("react").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=day-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"day-view.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/day-view.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAsB9E,KAAK,YAAY,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAC7C,WAAW,EAAE,IAAI,CAAC;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC9C,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAChD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,SAAS,CAAC;CAC9D,CAAC;AAEF,wBAAgB,OAAO,CAAC,CAAC,SAAS,iBAAiB,EAAE,EACjD,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,YAAY,GACf,EAAE,YAAY,CAAC,CAAC,CAAC,+BA8GjB"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { isToday } from "date-fns";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Tag } from "../core/tag";
|
|
4
|
+
import { useLocale } from "../../hooks/use-locale";
|
|
5
|
+
import { EventPill } from "./event-pill";
|
|
6
|
+
import { Calendar } from "../display/calendar";
|
|
7
|
+
import { getHourSlots, toDateKey, formatDay, formatWeekdayLong, formatMonthYear, formatHourLabel, formatFullDate, formatTime, } from "./page-calendar.utils";
|
|
8
|
+
const HOUR_HEIGHT = 48;
|
|
9
|
+
function getTopOffset(event) {
|
|
10
|
+
const hour = event.date.getHours();
|
|
11
|
+
const minutes = event.date.getMinutes();
|
|
12
|
+
return hour * HOUR_HEIGHT + (minutes / 60) * HOUR_HEIGHT;
|
|
13
|
+
}
|
|
14
|
+
export function DayView({ currentDate, onSlotClick, renderEvent, eventsByDate, onDateChange, onEventClick, }) {
|
|
15
|
+
const locale = useLocale();
|
|
16
|
+
const currentHourRef = useRef(null);
|
|
17
|
+
const scrollBodyRef = useRef(null);
|
|
18
|
+
const hours = getHourSlots();
|
|
19
|
+
const [selectedEvent, setSelectedEvent] = useState(null);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (scrollBodyRef.current && currentHourRef.current) {
|
|
22
|
+
const top = currentHourRef.current.offsetTop;
|
|
23
|
+
scrollBodyRef.current.scrollTop = top - scrollBodyRef.current.clientHeight / 2;
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
26
|
+
const dayKey = toDateKey(currentDate);
|
|
27
|
+
const events = eventsByDate.get(dayKey) || [];
|
|
28
|
+
const RenderOnDay = ({ date }) => {
|
|
29
|
+
const key = toDateKey(date);
|
|
30
|
+
const hasEvents = (eventsByDate.get(key) || []).length > 0;
|
|
31
|
+
const isSelected = toDateKey(date) === toDateKey(currentDate);
|
|
32
|
+
if (!hasEvents || isSelected)
|
|
33
|
+
return null;
|
|
34
|
+
return <span className="absolute bottom-0.5 left-1/2 h-1 w-1 -translate-x-1/2 rounded-full bg-primary"/>;
|
|
35
|
+
};
|
|
36
|
+
const handleEventClick = (event) => {
|
|
37
|
+
setSelectedEvent(event);
|
|
38
|
+
onEventClick(event);
|
|
39
|
+
};
|
|
40
|
+
return (<div className="flex flex-1 overflow-hidden">
|
|
41
|
+
<div className="flex flex-1 flex-col overflow-hidden">
|
|
42
|
+
<div className="flex flex-shrink-0 items-center gap-3 border-b border-border px-4 py-2">
|
|
43
|
+
<span className={`inline-flex h-8 w-8 items-center justify-center rounded-full font-bold ${isToday(currentDate) ? "bg-primary text-primary-foreground" : "text-foreground"}`}>
|
|
44
|
+
{formatDay(currentDate, locale)}
|
|
45
|
+
</span>
|
|
46
|
+
<div>
|
|
47
|
+
<div className="font-semibold">{formatWeekdayLong(currentDate, locale)}</div>
|
|
48
|
+
<div className="text-xs text-muted-foreground">{formatMonthYear(currentDate, locale)}</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div ref={scrollBodyRef} className="flex flex-1 items-start overflow-y-auto">
|
|
52
|
+
<div className="w-[60px] flex-shrink-0">
|
|
53
|
+
{hours.map((hour) => (<div key={hour} className="relative" style={{ height: HOUR_HEIGHT }}>
|
|
54
|
+
<span className="absolute -top-2.5 right-2 text-[10px] text-muted-foreground">
|
|
55
|
+
{hour === 0 ? "" : formatHourLabel(hour, locale)}
|
|
56
|
+
</span>
|
|
57
|
+
{hour === new Date().getHours() && <div ref={currentHourRef}/>}
|
|
58
|
+
</div>))}
|
|
59
|
+
</div>
|
|
60
|
+
<div className="relative flex-1 border-l border-card-border">
|
|
61
|
+
{hours.map((hour) => {
|
|
62
|
+
const slotDate = new Date(currentDate);
|
|
63
|
+
slotDate.setHours(hour, 0, 0, 0);
|
|
64
|
+
return (<div key={hour} className="cursor-pointer border-b border-border/50 hover:bg-muted/20" style={{ height: HOUR_HEIGHT }} onClick={() => onSlotClick?.(slotDate)}/>);
|
|
65
|
+
})}
|
|
66
|
+
{events.map((event) => (<div key={event.id} className="absolute left-1 right-1" style={{ top: getTopOffset(event), height: HOUR_HEIGHT }} onClick={(e) => e.stopPropagation()}>
|
|
67
|
+
<EventPill event={event} onClick={() => handleEventClick(event)}/>
|
|
68
|
+
</div>))}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
<div className="flex flex-col overflow-y-auto border-l border-card-border px-4">
|
|
73
|
+
<Calendar date={currentDate} markToday changeOnlyOnClick RenderOnDay={RenderOnDay} onChange={(d) => d && onDateChange(d)}/>
|
|
74
|
+
{selectedEvent && (<div className="flex flex-col gap-2 border-t p-3">
|
|
75
|
+
{renderEvent ? (renderEvent(selectedEvent)) : (<>
|
|
76
|
+
<div className="truncate text-sm font-semibold">{selectedEvent.title}</div>
|
|
77
|
+
<div className="text-xs text-muted-foreground">{formatFullDate(selectedEvent.date, locale)}</div>
|
|
78
|
+
<div className="text-xs text-muted-foreground">{formatTime(selectedEvent.date, locale)}</div>
|
|
79
|
+
<Tag theme={selectedEvent.className ? "custom" : "primary"} size="small" className={`self-start${selectedEvent.className ? ` ${selectedEvent.className}` : ""}`}/>
|
|
80
|
+
</>)}
|
|
81
|
+
</div>)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>);
|
|
84
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CalendarEvent } from "./page-calendar.types";
|
|
2
|
+
type EventPillProps = {
|
|
3
|
+
compact?: boolean;
|
|
4
|
+
onClick: () => void;
|
|
5
|
+
event: CalendarEvent;
|
|
6
|
+
};
|
|
7
|
+
export declare function EventPill({ event, onClick, compact }: EventPillProps): import("react").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=event-pill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-pill.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/event-pill.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAI3D,KAAK,cAAc,GAAG;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,OAAe,EAAE,EAAE,cAAc,+BAwB5E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Button } from "../core/button";
|
|
2
|
+
import { css } from "../../lib/dom";
|
|
3
|
+
import { formatEventTime } from "./page-calendar.utils";
|
|
4
|
+
export function EventPill({ event, onClick, compact = false }) {
|
|
5
|
+
const props = {
|
|
6
|
+
style: {
|
|
7
|
+
border: "0",
|
|
8
|
+
padding: "0 0.5rem",
|
|
9
|
+
height: "1.25rem",
|
|
10
|
+
borderRadius: "0.25rem",
|
|
11
|
+
},
|
|
12
|
+
className: css("w-full border-0 justify-start rounded text-xs truncate text-ellipsis overflow-hidden border leading-tight", event.className),
|
|
13
|
+
};
|
|
14
|
+
if (compact) {
|
|
15
|
+
return (<Button {...props} size="small" onClick={onClick} title={event.title} theme={event.className ? "raw" : "primary"}>
|
|
16
|
+
{event.title}
|
|
17
|
+
</Button>);
|
|
18
|
+
}
|
|
19
|
+
return (<Button {...props} size="small" onClick={onClick} title={event.title} theme={event.className ? "raw" : "primary"}>
|
|
20
|
+
<div className="truncate font-medium">{event.title}</div>
|
|
21
|
+
<div className="text-xs opacity-60">{formatEventTime(event.date)}</div>
|
|
22
|
+
</Button>);
|
|
23
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { PageCalendar } from "./page-calendar";
|
|
2
|
+
export type { CalendarEvent, CalendarFilter, ViewMode } from "./page-calendar.types";
|
|
3
|
+
export { toDateKey, groupEventsByDate, getMonthDays, getWeekDays, getHourSlots, formatEventTime, formatDay, formatWeekdayLong, formatWeekdayShort, formatMonthYear, formatMonthShort, formatHourLabel, formatFullDate, formatTime, getWeekNumber, } from "./page-calendar.utils";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EACH,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,UAAU,EACV,aAAa,GAChB,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { PageCalendar } from "./page-calendar";
|
|
2
|
+
export { toDateKey, groupEventsByDate, getMonthDays, getWeekDays, getHourSlots, formatEventTime, formatDay, formatWeekdayLong, formatWeekdayShort, formatMonthYear, formatMonthShort, formatHourLabel, formatFullDate, formatTime, getWeekNumber, } from "./page-calendar.utils";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CalendarEvent } from "./page-calendar.types";
|
|
2
|
+
type MonthViewProps = {
|
|
3
|
+
days: Date[];
|
|
4
|
+
currentDate: Date;
|
|
5
|
+
onDayClick: (date: Date) => void;
|
|
6
|
+
eventsByDate: Map<string, CalendarEvent[]>;
|
|
7
|
+
onEventClick: (event: CalendarEvent) => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function MonthView({ days, eventsByDate, currentDate, onEventClick, onDayClick }: MonthViewProps): import("react").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=month-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"month-view.d.ts","sourceRoot":"","sources":["../../../src/components/page-calendar/month-view.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAK3D,KAAK,cAAc,GAAG;IAClB,IAAI,EAAE,IAAI,EAAE,CAAC;IACb,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,cAAc,+BAuDtG"}
|