@sixthshift/design-system 0.1.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 +222 -0
- package/dist/styles.css +2 -0
- package/dist/theme.generated.css +438 -0
- package/package.json +238 -0
- package/src/components/Avatar/Avatar.tsx +19 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/Badge/Badge.tsx +59 -0
- package/src/components/Badge/index.ts +1 -0
- package/src/components/BarChart/BarChart.tsx +51 -0
- package/src/components/BarChart/index.ts +1 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +47 -0
- package/src/components/Breadcrumb/index.ts +5 -0
- package/src/components/Button/Button.tsx +157 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Calendar/Calendar.tsx +433 -0
- package/src/components/Calendar/calendar.hooks.ts +329 -0
- package/src/components/Calendar/calendar.types.ts +117 -0
- package/src/components/Calendar/index.ts +28 -0
- package/src/components/Card/Card.tsx +47 -0
- package/src/components/Card/index.ts +1 -0
- package/src/components/Checkbox/Checkbox.tsx +144 -0
- package/src/components/Checkbox/index.ts +1 -0
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +173 -0
- package/src/components/CheckboxGroup/index.ts +5 -0
- package/src/components/Code/Editor/Editor.tsx +161 -0
- package/src/components/Code/Editor/index.ts +2 -0
- package/src/components/Code/Editor/semanticTokenProvider.ts +69 -0
- package/src/components/Code/Editor/themes.ts +112 -0
- package/src/components/Code/ValidationStatus/ValidationStatus.tsx +81 -0
- package/src/components/Code/ValidationStatus/index.ts +1 -0
- package/src/components/Code/Workspace/StatusBar.tsx +47 -0
- package/src/components/Code/Workspace/Toolbar.tsx +47 -0
- package/src/components/Code/Workspace/Workspace.tsx +109 -0
- package/src/components/Code/Workspace/index.ts +3 -0
- package/src/components/ColorDot/ColorDot.tsx +50 -0
- package/src/components/ColorDot/index.ts +1 -0
- package/src/components/DatePicker/DatePicker.tsx +236 -0
- package/src/components/DatePicker/datepicker.hooks.ts +381 -0
- package/src/components/DatePicker/datepicker.types.ts +140 -0
- package/src/components/DatePicker/index.ts +12 -0
- package/src/components/DateRangePicker/DateRangePicker.tsx +127 -0
- package/src/components/DateRangePicker/daterangepicker.types.ts +53 -0
- package/src/components/DateRangePicker/index.ts +2 -0
- package/src/components/DateTimePicker/DateTimePicker.tsx +399 -0
- package/src/components/DateTimePicker/datetimepicker.types.ts +48 -0
- package/src/components/DateTimePicker/index.ts +2 -0
- package/src/components/DateTimeRangePicker/DateTimeRangePicker.tsx +679 -0
- package/src/components/DateTimeRangePicker/datetimerangepicker.types.ts +62 -0
- package/src/components/DateTimeRangePicker/index.ts +2 -0
- package/src/components/EmptyState/EmptyState.tsx +29 -0
- package/src/components/EmptyState/index.ts +1 -0
- package/src/components/Field/Field.tsx +60 -0
- package/src/components/Field/index.ts +1 -0
- package/src/components/FormField/FormField.tsx +55 -0
- package/src/components/FormField/index.ts +2 -0
- package/src/components/HeatMap/HeatMapCalendar.tsx +127 -0
- package/src/components/HeatMap/HeatMapMatrix.tsx +75 -0
- package/src/components/HeatMap/heat-map.utils.ts +15 -0
- package/src/components/HeatMap/index.ts +3 -0
- package/src/components/HoverCard/HoverCard.tsx +83 -0
- package/src/components/HoverCard/components/HoverCardContent.tsx +30 -0
- package/src/components/HoverCard/components/HoverCardContext.tsx +22 -0
- package/src/components/HoverCard/components/HoverCardTrigger.tsx +32 -0
- package/src/components/HoverCard/index.ts +3 -0
- package/src/components/Input/Input.tsx +48 -0
- package/src/components/Input/index.ts +1 -0
- package/src/components/LineChart/LineChart.tsx +251 -0
- package/src/components/LineChart/index.ts +1 -0
- package/src/components/Markdown/Markdown.tsx +40 -0
- package/src/components/Markdown/index.ts +1 -0
- package/src/components/Message/Message.tsx +59 -0
- package/src/components/Message/components/MessageBody.tsx +9 -0
- package/src/components/Message/components/MessageDescription.tsx +9 -0
- package/src/components/Message/components/MessageIcon.tsx +13 -0
- package/src/components/Message/components/MessageTitle.tsx +9 -0
- package/src/components/Message/index.ts +10 -0
- package/src/components/MetricList/MetricList.tsx +13 -0
- package/src/components/MetricList/MetricRow.tsx +30 -0
- package/src/components/MetricList/index.ts +2 -0
- package/src/components/Modal/Modal.tsx +146 -0
- package/src/components/Modal/components/ModalBody.tsx +9 -0
- package/src/components/Modal/components/ModalContext.tsx +27 -0
- package/src/components/Modal/components/ModalFooter.tsx +9 -0
- package/src/components/Modal/components/ModalHeader.tsx +29 -0
- package/src/components/Modal/components/index.ts +9 -0
- package/src/components/Modal/index.ts +13 -0
- package/src/components/NavBottom/NavBottom.tsx +53 -0
- package/src/components/NavBottom/index.ts +3 -0
- package/src/components/NavSide/NavItem.tsx +39 -0
- package/src/components/NavSide/NavSide.tsx +40 -0
- package/src/components/NavSide/index.ts +2 -0
- package/src/components/NavSide/types.ts +36 -0
- package/src/components/Pagination/Pagination.tsx +86 -0
- package/src/components/Pagination/index.ts +2 -0
- package/src/components/Popover/Popover.tsx +68 -0
- package/src/components/Popover/components/PopoverBody.tsx +32 -0
- package/src/components/Popover/components/PopoverClose.tsx +26 -0
- package/src/components/Popover/components/PopoverContext.tsx +24 -0
- package/src/components/Popover/components/PopoverTrigger.tsx +31 -0
- package/src/components/Popover/index.ts +10 -0
- package/src/components/ProgressBar/ProgressBar.tsx +42 -0
- package/src/components/ProgressBar/index.ts +1 -0
- package/src/components/RadioButton/RadioButton.tsx +89 -0
- package/src/components/RadioButton/index.ts +1 -0
- package/src/components/RadioButtonGroup/RadioButtonGroup.tsx +193 -0
- package/src/components/RadioButtonGroup/index.ts +5 -0
- package/src/components/SearchInput/SearchInput.tsx +45 -0
- package/src/components/SearchInput/index.ts +2 -0
- package/src/components/Select/Select.tsx +289 -0
- package/src/components/Select/SelectDropdown.tsx +90 -0
- package/src/components/Select/SelectTrigger.tsx +130 -0
- package/src/components/Select/index.ts +3 -0
- package/src/components/Select/useSelectKeyboard.ts +111 -0
- package/src/components/Separator/Separator.tsx +20 -0
- package/src/components/Separator/index.ts +1 -0
- package/src/components/Sheet/Sheet.tsx +136 -0
- package/src/components/Sheet/components/SheetBody.tsx +9 -0
- package/src/components/Sheet/components/SheetContext.tsx +23 -0
- package/src/components/Sheet/components/SheetFooter.tsx +9 -0
- package/src/components/Sheet/components/SheetHeader.tsx +29 -0
- package/src/components/Sheet/components/index.ts +9 -0
- package/src/components/Sheet/index.ts +13 -0
- package/src/components/Skeleton/Skeleton.tsx +7 -0
- package/src/components/Skeleton/index.ts +1 -0
- package/src/components/Sparkline/Sparkline.tsx +93 -0
- package/src/components/Sparkline/index.ts +1 -0
- package/src/components/Spinner/Spinner.tsx +41 -0
- package/src/components/Spinner/index.ts +1 -0
- package/src/components/StatsCard/StatsCard.tsx +40 -0
- package/src/components/StatsCard/index.ts +1 -0
- package/src/components/Switch/Switch.tsx +128 -0
- package/src/components/Switch/index.ts +1 -0
- package/src/components/Tabs/Tabs.tsx +49 -0
- package/src/components/Tabs/components/TabsContext.tsx +35 -0
- package/src/components/Tabs/components/TabsList.tsx +98 -0
- package/src/components/Tabs/components/TabsPanels.tsx +26 -0
- package/src/components/Tabs/components/TabsTrigger.tsx +69 -0
- package/src/components/Tabs/index.ts +3 -0
- package/src/components/TagChip/TagChip.tsx +46 -0
- package/src/components/TagChip/index.ts +1 -0
- package/src/components/TagInput/TagInput.tsx +60 -0
- package/src/components/TagInput/index.ts +1 -0
- package/src/components/Text/Text.tsx +35 -0
- package/src/components/Text/index.ts +1 -0
- package/src/components/TextInline/TextInline.tsx +35 -0
- package/src/components/TextInline/index.ts +1 -0
- package/src/components/Textarea/Textarea.tsx +20 -0
- package/src/components/Textarea/index.ts +1 -0
- package/src/components/TimePicker/PeriodSelector.tsx +28 -0
- package/src/components/TimePicker/TimeColumn.tsx +62 -0
- package/src/components/TimePicker/TimePicker.tsx +323 -0
- package/src/components/TimePicker/index.ts +7 -0
- package/src/components/TimePicker/timepicker.hooks.ts +173 -0
- package/src/components/TimePicker/timepicker.types.ts +101 -0
- package/src/components/Toast/Toast.tsx +111 -0
- package/src/components/Toast/index.ts +1 -0
- package/src/components/Toggle/Toggle.tsx +72 -0
- package/src/components/Toggle/index.ts +1 -0
- package/src/components/ToggleGroup/ToggleGroup.tsx +14 -0
- package/src/components/ToggleGroup/ToggleGroupContainer.tsx +19 -0
- package/src/components/ToggleGroup/ToggleGroupItem.tsx +51 -0
- package/src/components/ToggleGroup/ToggleGroupMultiple.tsx +61 -0
- package/src/components/ToggleGroup/ToggleGroupSingle.tsx +105 -0
- package/src/components/ToggleGroup/index.ts +2 -0
- package/src/components/ToggleGroup/toggleGroup.types.ts +55 -0
- package/src/components/Tooltip/Tooltip.tsx +66 -0
- package/src/components/Tooltip/components/TooltipBody.tsx +30 -0
- package/src/components/Tooltip/components/TooltipContext.tsx +22 -0
- package/src/components/Tooltip/components/TooltipTrigger.tsx +27 -0
- package/src/components/Tooltip/index.ts +9 -0
- package/src/date-time/arithmetic.ts +101 -0
- package/src/date-time/boundaries.ts +91 -0
- package/src/date-time/compare.ts +85 -0
- package/src/date-time/duration.ts +63 -0
- package/src/date-time/elapsed.ts +18 -0
- package/src/date-time/format.ts +722 -0
- package/src/date-time/index.ts +279 -0
- package/src/date-time/now.ts +70 -0
- package/src/date-time/parse.ts +170 -0
- package/src/date-time/serialize.ts +90 -0
- package/src/date-time/timezone.ts +47 -0
- package/src/date-time/validate.ts +278 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/useCollapsible.ts +16 -0
- package/src/hooks/useControllableState.ts +54 -0
- package/src/hooks/useDebouncedCallback.ts +21 -0
- package/src/hooks/useDebouncedState.ts +20 -0
- package/src/hooks/useDeviceFormFactor.ts +49 -0
- package/src/hooks/useLocalStorage.ts +67 -0
- package/src/hooks/useMergedFloatingRef.ts +29 -0
- package/src/hooks/usePresence.ts +127 -0
- package/src/hooks/useStack.ts +99 -0
- package/src/hooks/useTheme.ts +105 -0
- package/src/internal/Slot.tsx +79 -0
- package/src/internal/index.ts +2 -0
- package/src/internal/rovingFocus.ts +39 -0
- package/src/internal/types.ts +10 -0
- package/src/lib/EmptyBoundary.tsx +12 -0
- package/src/lib/ErrorBoundary.tsx +48 -0
- package/src/lib/contexts/ComponentsContext/ComponentsContext.tsx +34 -0
- package/src/lib/contexts/ComponentsContext/index.ts +1 -0
- package/src/lib/contexts/OverlayContext/OverlayContext.tsx +93 -0
- package/src/lib/contexts/OverlayContext/hooks/useModal.tsx +125 -0
- package/src/lib/contexts/OverlayContext/hooks/useToast.ts +80 -0
- package/src/lib/contexts/OverlayContext/index.ts +6 -0
- package/src/lib/format.ts +51 -0
- package/src/lib/utils.ts +10 -0
- package/src/lib/withEmpty.tsx +14 -0
- package/src/lib/withErrorBoundary.tsx +16 -0
- package/src/lib/withSuspense.tsx +16 -0
- package/src/lib/withSuspenseAndErrorBoundary.tsx +26 -0
- package/src/styles/base.css +41 -0
- package/src/theme/index.ts +37 -0
- package/src/theme/palette.json +100 -0
- package/src/theme/palette.schema.json +40 -0
- package/src/theme/schema.ts +122 -0
- package/src/theme/theme.json +349 -0
- package/src/theme/theme.schema.json +876 -0
- package/src/theme/typography.json +7 -0
- package/src/theme/typography.schema.json +36 -0
- package/src/typography/Body.tsx +8 -0
- package/src/typography/Caption.tsx +8 -0
- package/src/typography/Code.tsx +8 -0
- package/src/typography/Display.tsx +8 -0
- package/src/typography/Emphasis.tsx +8 -0
- package/src/typography/Heading.tsx +23 -0
- package/src/typography/Label.tsx +10 -0
- package/src/typography/Lead.tsx +8 -0
- package/src/typography/Mono.tsx +8 -0
- package/src/typography/Muted.tsx +8 -0
- package/src/typography/SectionTitle.tsx +8 -0
- package/src/typography/Subtitle.tsx +8 -0
- package/src/typography/Timestamp.tsx +8 -0
- package/src/typography/index.ts +10 -0
- package/tailwind.config.ts +261 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { StackItem } from "@sixthshift/design-system/hooks";
|
|
2
|
+
import { Toast, type ToastProps } from "@sixthshift/design-system/toast";
|
|
3
|
+
import { type FunctionComponent, useCallback, useEffect, useId, useRef } from "react";
|
|
4
|
+
import { useOverlayContext } from "../OverlayContext";
|
|
5
|
+
|
|
6
|
+
// Default auto-dismiss duration in milliseconds
|
|
7
|
+
const DEFAULT_DURATION = 5000;
|
|
8
|
+
|
|
9
|
+
// Native replacements for lodash functions
|
|
10
|
+
const isFunction = (value: unknown): value is FunctionComponent<ToastProps> => typeof value === "function";
|
|
11
|
+
|
|
12
|
+
const isPlainObject = (value: unknown): value is ToastPropsWithDuration => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13
|
+
|
|
14
|
+
type ToastPropsWithDuration = Omit<ToastProps, "onClose"> & {
|
|
15
|
+
/** Auto-dismiss duration in ms. Set to 0 to disable. Default: 5000 */
|
|
16
|
+
duration?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Toast stack item - extends base StackItem with component and additional props
|
|
21
|
+
* that are passed through to the Toast component in OverlayContext
|
|
22
|
+
*/
|
|
23
|
+
type ToastStackItem = StackItem & {
|
|
24
|
+
component: FunctionComponent<ToastProps>;
|
|
25
|
+
onClose?: () => void;
|
|
26
|
+
} & Partial<Omit<ToastProps, "onClose">>;
|
|
27
|
+
|
|
28
|
+
export const useToast = (args: ToastPropsWithDuration | FunctionComponent<ToastProps>) => {
|
|
29
|
+
const {
|
|
30
|
+
toastStack: [, dispatch],
|
|
31
|
+
} = useOverlayContext();
|
|
32
|
+
|
|
33
|
+
const id = useId();
|
|
34
|
+
|
|
35
|
+
const customComponent = isFunction(args) ? args : null;
|
|
36
|
+
const props = isPlainObject(args) ? args : ({} as ToastPropsWithDuration);
|
|
37
|
+
const { duration = DEFAULT_DURATION, ...toastPropsRaw } = props;
|
|
38
|
+
|
|
39
|
+
const closeToast = useCallback(() => {
|
|
40
|
+
dispatch({ type: "remove", id, transition: { duration: 300 } });
|
|
41
|
+
}, [dispatch, id]);
|
|
42
|
+
|
|
43
|
+
// `openToast` has to be both referentially stable — callers put it in effect
|
|
44
|
+
// dependency arrays — and able to see the current props. A ref refreshed after
|
|
45
|
+
// every render gives both.
|
|
46
|
+
//
|
|
47
|
+
// It previously memoised the props object against JSON.stringify(props) as a
|
|
48
|
+
// cache key. JSON.stringify silently drops function-valued properties, so a
|
|
49
|
+
// changed `onAction` whose serialisable fields were identical did not
|
|
50
|
+
// invalidate the key, and `openToast` kept firing the stale closure.
|
|
51
|
+
const latest = useRef({ customComponent, toastProps: toastPropsRaw, duration });
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
latest.current = { customComponent, toastProps: toastPropsRaw, duration };
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const openToast = useCallback(() => {
|
|
57
|
+
const { customComponent: component, toastProps, duration: autoDismiss } = latest.current;
|
|
58
|
+
|
|
59
|
+
dispatch({
|
|
60
|
+
type: "push",
|
|
61
|
+
item: {
|
|
62
|
+
id,
|
|
63
|
+
component: component ?? Toast,
|
|
64
|
+
onClose: closeToast,
|
|
65
|
+
standalone: false, // OverlayContext handles positioning
|
|
66
|
+
...toastProps,
|
|
67
|
+
} as ToastStackItem,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Auto-dismiss if duration is set
|
|
71
|
+
if (autoDismiss > 0) {
|
|
72
|
+
setTimeout(closeToast, autoDismiss);
|
|
73
|
+
}
|
|
74
|
+
}, [dispatch, id, closeToast]);
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
openToast,
|
|
78
|
+
closeToast,
|
|
79
|
+
};
|
|
80
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type { ModalProps } from "@sixthshift/design-system/modal";
|
|
2
|
+
// Re-export Modal from primitives for convenience
|
|
3
|
+
export { Modal } from "@sixthshift/design-system/modal";
|
|
4
|
+
export * from "./hooks/useModal";
|
|
5
|
+
export * from "./hooks/useToast";
|
|
6
|
+
export * from "./OverlayContext";
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities for common display patterns
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const BYTE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB"] as const;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Format a byte count for display, e.g. `formatBytes(1536)` -> `"1.50 KB"`.
|
|
9
|
+
*
|
|
10
|
+
* Total over every finite input:
|
|
11
|
+
* - negative values format their magnitude with a leading sign, so the function
|
|
12
|
+
* is usable for deltas
|
|
13
|
+
* - values above the largest unit stay in PB rather than running off the end of
|
|
14
|
+
* the unit list (PB already exceeds Number.MAX_SAFE_INTEGER bytes)
|
|
15
|
+
* - values below 1 byte stay in B
|
|
16
|
+
*
|
|
17
|
+
* Non-finite input (NaN, +/-Infinity) has no representation, so it returns an
|
|
18
|
+
* em dash rather than a number that would be wrong.
|
|
19
|
+
*/
|
|
20
|
+
export function formatBytes(bytes: number): string {
|
|
21
|
+
if (!Number.isFinite(bytes)) return "—";
|
|
22
|
+
if (bytes === 0) return "0 B";
|
|
23
|
+
|
|
24
|
+
// Repeated division rather than Math.log(bytes) / Math.log(1024): it is exact
|
|
25
|
+
// at the unit boundaries, needs no clamping of a computed index, and cannot
|
|
26
|
+
// produce a negative or out-of-range index for very small or very large input.
|
|
27
|
+
let value = Math.abs(bytes);
|
|
28
|
+
let unit = 0;
|
|
29
|
+
while (value >= 1024 && unit < BYTE_UNITS.length - 1) {
|
|
30
|
+
value /= 1024;
|
|
31
|
+
unit++;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return `${bytes < 0 ? "-" : ""}${value.toFixed(2)} ${BYTE_UNITS[unit]}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Format seconds to human-readable uptime (e.g., "2d 5h 30m")
|
|
39
|
+
*/
|
|
40
|
+
export function formatUptime(seconds: number): string {
|
|
41
|
+
const days = Math.floor(seconds / 86400);
|
|
42
|
+
const hours = Math.floor((seconds % 86400) / 3600);
|
|
43
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
44
|
+
|
|
45
|
+
const parts: string[] = [];
|
|
46
|
+
if (days > 0) parts.push(`${days}d`);
|
|
47
|
+
if (hours > 0) parts.push(`${hours}h`);
|
|
48
|
+
if (minutes > 0) parts.push(`${minutes}m`);
|
|
49
|
+
|
|
50
|
+
return parts.length > 0 ? parts.join(" ") : "< 1m";
|
|
51
|
+
}
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type ClassValue, clsx } from "clsx";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Merge Tailwind classes with clsx
|
|
6
|
+
* Handles conditional classes and resolves conflicts
|
|
7
|
+
*/
|
|
8
|
+
export function cn(...inputs: ClassValue[]) {
|
|
9
|
+
return twMerge(clsx(inputs));
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
export function withEmpty<P extends object>(Component: ComponentType<P>, isEmpty: (props: P) => boolean, fallback: ReactNode) {
|
|
4
|
+
function WithEmpty(props: P) {
|
|
5
|
+
if (isEmpty(props)) {
|
|
6
|
+
return <>{fallback}</>;
|
|
7
|
+
}
|
|
8
|
+
return <Component {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
WithEmpty.displayName = `withEmpty(${Component.displayName || Component.name || "Component"})`;
|
|
12
|
+
|
|
13
|
+
return WithEmpty;
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
|
+
import { ErrorBoundary, type ErrorFallbackProps } from "./ErrorBoundary";
|
|
3
|
+
|
|
4
|
+
export function withErrorBoundary<P extends object>(Component: ComponentType<P>, fallback: ReactNode | ((props: ErrorFallbackProps) => ReactNode)) {
|
|
5
|
+
function WithErrorBoundary(props: P) {
|
|
6
|
+
return (
|
|
7
|
+
<ErrorBoundary fallback={fallback}>
|
|
8
|
+
<Component {...props} />
|
|
9
|
+
</ErrorBoundary>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
WithErrorBoundary.displayName = `withErrorBoundary(${Component.displayName || Component.name || "Component"})`;
|
|
14
|
+
|
|
15
|
+
return WithErrorBoundary;
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
|
+
import { Suspense } from "react";
|
|
3
|
+
|
|
4
|
+
export function withSuspense<P extends object>(Component: ComponentType<P>, fallback: ReactNode) {
|
|
5
|
+
function WithSuspense(props: P) {
|
|
6
|
+
return (
|
|
7
|
+
<Suspense fallback={fallback}>
|
|
8
|
+
<Component {...props} />
|
|
9
|
+
</Suspense>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
WithSuspense.displayName = `withSuspense(${Component.displayName || Component.name || "Component"})`;
|
|
14
|
+
|
|
15
|
+
return WithSuspense;
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
|
+
import { Suspense } from "react";
|
|
3
|
+
import { ErrorBoundary, type ErrorFallbackProps } from "./ErrorBoundary";
|
|
4
|
+
|
|
5
|
+
type Options = {
|
|
6
|
+
fallback: ReactNode;
|
|
7
|
+
errorFallback: ReactNode | ((props: ErrorFallbackProps) => ReactNode);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function withSuspenseAndErrorBoundary<P extends object>(Component: ComponentType<P>, options: Options) {
|
|
11
|
+
const { fallback, errorFallback } = options;
|
|
12
|
+
|
|
13
|
+
function WithSuspenseAndErrorBoundary(props: P) {
|
|
14
|
+
return (
|
|
15
|
+
<ErrorBoundary fallback={errorFallback}>
|
|
16
|
+
<Suspense fallback={fallback}>
|
|
17
|
+
<Component {...props} />
|
|
18
|
+
</Suspense>
|
|
19
|
+
</ErrorBoundary>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
WithSuspenseAndErrorBoundary.displayName = `withSuspenseAndErrorBoundary(${Component.displayName || Component.name || "Component"})`;
|
|
24
|
+
|
|
25
|
+
return WithSuspenseAndErrorBoundary;
|
|
26
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PA Design System - Global Styles
|
|
3
|
+
*
|
|
4
|
+
* Theme tokens (CSS variables) are provided by @sixthshift/design-system/theme.css
|
|
5
|
+
* which is generated from src/theme/theme.json and src/theme/palette.json
|
|
6
|
+
*
|
|
7
|
+
* Import order in consumers:
|
|
8
|
+
* import '@sixthshift/design-system/theme.css'; // CSS variables
|
|
9
|
+
* import '@sixthshift/design-system/styles.css'; // Tailwind + base styles
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
@import "tailwindcss";
|
|
13
|
+
@config "../../tailwind.config.ts";
|
|
14
|
+
|
|
15
|
+
/* =============================================================================
|
|
16
|
+
BASE STYLES
|
|
17
|
+
============================================================================= */
|
|
18
|
+
|
|
19
|
+
@layer base {
|
|
20
|
+
* {
|
|
21
|
+
@apply border-border-normal;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
@apply bg-bg-normal text-fg-normal;
|
|
26
|
+
font-family: var(--font-sans);
|
|
27
|
+
font-feature-settings:
|
|
28
|
+
'rlig' 1,
|
|
29
|
+
'calt' 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* Smooth scrolling */
|
|
33
|
+
html {
|
|
34
|
+
scroll-behavior: smooth;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Focus visible for keyboard navigation */
|
|
38
|
+
:focus-visible {
|
|
39
|
+
@apply outline-hidden ring-2 ring-focus-ring ring-offset-2 ring-offset-bg-normal;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Exports
|
|
3
|
+
*
|
|
4
|
+
* Re-exports schema types and utilities for use in other packages.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type {
|
|
8
|
+
BgKey,
|
|
9
|
+
BgToken,
|
|
10
|
+
BorderKey,
|
|
11
|
+
BorderToken,
|
|
12
|
+
ColorMode,
|
|
13
|
+
ColorModeSchema,
|
|
14
|
+
ColorToken,
|
|
15
|
+
Context,
|
|
16
|
+
CSSVarName,
|
|
17
|
+
Feedback,
|
|
18
|
+
FgKey,
|
|
19
|
+
FgToken,
|
|
20
|
+
HexValue,
|
|
21
|
+
Hierarchy,
|
|
22
|
+
HSLValue,
|
|
23
|
+
Semantic,
|
|
24
|
+
ThemeSchema,
|
|
25
|
+
TokenKey,
|
|
26
|
+
} from "./schema";
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
contexts,
|
|
30
|
+
cssVar,
|
|
31
|
+
feedback,
|
|
32
|
+
getAllTokenNames,
|
|
33
|
+
getTokenNames,
|
|
34
|
+
hierarchy,
|
|
35
|
+
hsl,
|
|
36
|
+
semantics,
|
|
37
|
+
} from "./schema";
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "./palette.schema.json",
|
|
3
|
+
"emerald": {
|
|
4
|
+
"50": "#f2fafb",
|
|
5
|
+
"100": "#d6eef0",
|
|
6
|
+
"200": "#addde0",
|
|
7
|
+
"300": "#7cc4c8",
|
|
8
|
+
"400": "#4ba5a9",
|
|
9
|
+
"500": "#368086",
|
|
10
|
+
"600": "#2c666c",
|
|
11
|
+
"700": "#234e53",
|
|
12
|
+
"800": "#19393d",
|
|
13
|
+
"900": "#11292c",
|
|
14
|
+
"950": "#0a1a1d"
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
"topaz": {
|
|
18
|
+
"50": "#fff7f0",
|
|
19
|
+
"100": "#ffe5d1",
|
|
20
|
+
"200": "#fbc89f",
|
|
21
|
+
"300": "#f0a066",
|
|
22
|
+
"400": "#d9722e",
|
|
23
|
+
"500": "#c4530a",
|
|
24
|
+
"600": "#9f4007",
|
|
25
|
+
"700": "#7b2e06",
|
|
26
|
+
"800": "#5a2105",
|
|
27
|
+
"900": "#3d1503",
|
|
28
|
+
"950": "#230c02"
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
"ruby": {
|
|
32
|
+
"50": "#fff5f6",
|
|
33
|
+
"100": "#fde1e4",
|
|
34
|
+
"200": "#f8bac3",
|
|
35
|
+
"300": "#ec8796",
|
|
36
|
+
"400": "#d55368",
|
|
37
|
+
"500": "#c33341",
|
|
38
|
+
"600": "#9e2533",
|
|
39
|
+
"700": "#7a1b27",
|
|
40
|
+
"800": "#57131c",
|
|
41
|
+
"900": "#3a0c13",
|
|
42
|
+
"950": "#21070b"
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
"ocean": {
|
|
46
|
+
"50": "#f0f4fa",
|
|
47
|
+
"100": "#dce6f4",
|
|
48
|
+
"200": "#b9cde9",
|
|
49
|
+
"300": "#8fafd9",
|
|
50
|
+
"400": "#6691c7",
|
|
51
|
+
"500": "#4573ae",
|
|
52
|
+
"600": "#355a8c",
|
|
53
|
+
"700": "#034078",
|
|
54
|
+
"800": "#022f5a",
|
|
55
|
+
"900": "#001f54",
|
|
56
|
+
"950": "#0a1128"
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
"sky": {
|
|
60
|
+
"50": "#effcff",
|
|
61
|
+
"100": "#d6f5fb",
|
|
62
|
+
"200": "#b3ecf7",
|
|
63
|
+
"300": "#7fdff0",
|
|
64
|
+
"400": "#44c9e2",
|
|
65
|
+
"500": "#1282a2",
|
|
66
|
+
"600": "#0f6b86",
|
|
67
|
+
"700": "#10576d",
|
|
68
|
+
"800": "#12475a",
|
|
69
|
+
"900": "#133c4c",
|
|
70
|
+
"950": "#062733"
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
"earth": {
|
|
74
|
+
"50": "#fefcfb",
|
|
75
|
+
"100": "#faf6f4",
|
|
76
|
+
"200": "#f2ebe7",
|
|
77
|
+
"300": "#e8ddd6",
|
|
78
|
+
"400": "#d4c4b9",
|
|
79
|
+
"500": "#b8a192",
|
|
80
|
+
"600": "#9a816f",
|
|
81
|
+
"700": "#7d6555",
|
|
82
|
+
"800": "#5e4b40",
|
|
83
|
+
"900": "#3d302a",
|
|
84
|
+
"950": "#211916"
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
"slate": {
|
|
88
|
+
"50": "#f8fafc",
|
|
89
|
+
"100": "#f1f5f9",
|
|
90
|
+
"200": "#e2e8f0",
|
|
91
|
+
"300": "#cbd5e1",
|
|
92
|
+
"400": "#94a3b8",
|
|
93
|
+
"500": "#64748b",
|
|
94
|
+
"600": "#475569",
|
|
95
|
+
"700": "#334155",
|
|
96
|
+
"800": "#1e293b",
|
|
97
|
+
"900": "#0f172a",
|
|
98
|
+
"950": "#020617"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "PA Palette",
|
|
4
|
+
"description": "Color palette definition for Personal Assistant",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"$schema": {
|
|
8
|
+
"type": "string"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"additionalProperties": {
|
|
12
|
+
"$ref": "#/$defs/colorScale"
|
|
13
|
+
},
|
|
14
|
+
"$defs": {
|
|
15
|
+
"hexColor": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"pattern": "^#[0-9a-fA-F]{6}$",
|
|
18
|
+
"description": "Hex color value (e.g., #818cf8)"
|
|
19
|
+
},
|
|
20
|
+
"colorScale": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"description": "A color scale with steps from 50 to 950",
|
|
23
|
+
"properties": {
|
|
24
|
+
"50": { "$ref": "#/$defs/hexColor", "description": "Lightest shade" },
|
|
25
|
+
"100": { "$ref": "#/$defs/hexColor" },
|
|
26
|
+
"200": { "$ref": "#/$defs/hexColor" },
|
|
27
|
+
"300": { "$ref": "#/$defs/hexColor" },
|
|
28
|
+
"400": { "$ref": "#/$defs/hexColor" },
|
|
29
|
+
"500": { "$ref": "#/$defs/hexColor", "description": "Base shade" },
|
|
30
|
+
"600": { "$ref": "#/$defs/hexColor" },
|
|
31
|
+
"700": { "$ref": "#/$defs/hexColor" },
|
|
32
|
+
"800": { "$ref": "#/$defs/hexColor" },
|
|
33
|
+
"900": { "$ref": "#/$defs/hexColor" },
|
|
34
|
+
"950": { "$ref": "#/$defs/hexColor", "description": "Darkest shade" }
|
|
35
|
+
},
|
|
36
|
+
"required": ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"],
|
|
37
|
+
"additionalProperties": false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Schema
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the PA design system token structure.
|
|
5
|
+
* These types enforce the naming convention: {context}-{semantic}
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// PRIMITIVES
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
/** HSL color value without wrapper, e.g., "239 84% 67%" */
|
|
13
|
+
export type HSLValue = string;
|
|
14
|
+
|
|
15
|
+
/** Hex color value, e.g., "#6366f1" */
|
|
16
|
+
export type HexValue = string;
|
|
17
|
+
|
|
18
|
+
/** Color mode */
|
|
19
|
+
export type ColorMode = "light" | "dark";
|
|
20
|
+
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// TOKEN STRUCTURE
|
|
23
|
+
// =============================================================================
|
|
24
|
+
|
|
25
|
+
/** Contexts - what CSS property this affects */
|
|
26
|
+
export const contexts = ["bg", "fg", "border"] as const;
|
|
27
|
+
export type Context = (typeof contexts)[number];
|
|
28
|
+
|
|
29
|
+
/** Hierarchy semantics - visual weight */
|
|
30
|
+
export const hierarchy = ["strong", "normal", "subtle"] as const;
|
|
31
|
+
export type Hierarchy = (typeof hierarchy)[number];
|
|
32
|
+
|
|
33
|
+
/** Feedback semantics - meaning */
|
|
34
|
+
export const feedback = ["success", "warning", "danger"] as const;
|
|
35
|
+
export type Feedback = (typeof feedback)[number];
|
|
36
|
+
|
|
37
|
+
/** All semantics */
|
|
38
|
+
export const semantics = [...hierarchy, ...feedback] as const;
|
|
39
|
+
export type Semantic = (typeof semantics)[number];
|
|
40
|
+
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// TOKEN NAMES (derived types)
|
|
43
|
+
// =============================================================================
|
|
44
|
+
|
|
45
|
+
/** Background tokens: bg-{semantic} */
|
|
46
|
+
export type BgToken = `bg-${Semantic}`;
|
|
47
|
+
|
|
48
|
+
/** Foreground tokens: fg-{semantic} | fg-on-{semantic} */
|
|
49
|
+
export type FgToken = `fg-${Semantic}` | `fg-on-${Semantic}`;
|
|
50
|
+
|
|
51
|
+
/** Border tokens: border-{semantic} */
|
|
52
|
+
export type BorderToken = `border-${Semantic}`;
|
|
53
|
+
|
|
54
|
+
/** All color tokens */
|
|
55
|
+
export type ColorToken = BgToken | FgToken | BorderToken;
|
|
56
|
+
|
|
57
|
+
/** CSS variable name format */
|
|
58
|
+
export type CSSVarName = `--${ColorToken}`;
|
|
59
|
+
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// THEME SCHEMA
|
|
62
|
+
// =============================================================================
|
|
63
|
+
|
|
64
|
+
/** Background token keys */
|
|
65
|
+
export type BgKey = `bg-${Semantic}`;
|
|
66
|
+
|
|
67
|
+
/** Foreground token keys */
|
|
68
|
+
export type FgKey = `fg-${Semantic}` | `fg-on-${Semantic}`;
|
|
69
|
+
|
|
70
|
+
/** Border token keys */
|
|
71
|
+
export type BorderKey = `border-${Semantic}`;
|
|
72
|
+
|
|
73
|
+
/** All token keys */
|
|
74
|
+
export type TokenKey = BgKey | FgKey | BorderKey;
|
|
75
|
+
|
|
76
|
+
/** Color mode schema (light or dark) - flat structure */
|
|
77
|
+
export type ColorModeSchema = {
|
|
78
|
+
[K in TokenKey]: HexValue;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/** Complete theme schema */
|
|
82
|
+
export type ThemeSchema = {
|
|
83
|
+
$schema?: string;
|
|
84
|
+
name: string;
|
|
85
|
+
version: string;
|
|
86
|
+
light: ColorModeSchema;
|
|
87
|
+
dark: ColorModeSchema;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// =============================================================================
|
|
91
|
+
// UTILITIES
|
|
92
|
+
// =============================================================================
|
|
93
|
+
|
|
94
|
+
/** Get all token names for a context */
|
|
95
|
+
export function getTokenNames(context: "bg"): BgToken[];
|
|
96
|
+
export function getTokenNames(context: "fg"): FgToken[];
|
|
97
|
+
export function getTokenNames(context: "border"): BorderToken[];
|
|
98
|
+
export function getTokenNames(context: Context): ColorToken[] {
|
|
99
|
+
switch (context) {
|
|
100
|
+
case "bg":
|
|
101
|
+
return semantics.map((s) => `bg-${s}` as BgToken);
|
|
102
|
+
case "fg":
|
|
103
|
+
return [...semantics.map((s) => `fg-${s}` as FgToken), ...semantics.map((s) => `fg-on-${s}` as FgToken)];
|
|
104
|
+
case "border":
|
|
105
|
+
return semantics.map((s) => `border-${s}` as BorderToken);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Get all token names */
|
|
110
|
+
export function getAllTokenNames(): ColorToken[] {
|
|
111
|
+
return [...getTokenNames("bg"), ...getTokenNames("fg"), ...getTokenNames("border")];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Type-safe CSS var reference */
|
|
115
|
+
export function cssVar(token: ColorToken): string {
|
|
116
|
+
return `var(--${token})`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Type-safe HSL wrapper for Tailwind */
|
|
120
|
+
export function hsl(token: ColorToken): string {
|
|
121
|
+
return `hsl(var(--${token}))`;
|
|
122
|
+
}
|