sid-ui 0.0.0-stage → 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.
Files changed (116) hide show
  1. package/README.md +54 -2
  2. package/package.json +51 -4
  3. package/src/brand/BrandFooter.tsx +45 -0
  4. package/src/brand/BrandHeading.tsx +24 -0
  5. package/src/brand/BrandLockup.tsx +47 -0
  6. package/src/brand/JoinedLogo.tsx +67 -0
  7. package/src/brand/JoinedMark.tsx +76 -0
  8. package/src/brand/geometry.ts +26 -0
  9. package/src/brand/index.ts +11 -0
  10. package/src/brand/name.ts +5 -0
  11. package/src/brand/paint.tsx +56 -0
  12. package/src/components/Action.tsx +44 -0
  13. package/src/components/AddressSelector.tsx +99 -0
  14. package/src/components/BarChart.tsx +132 -0
  15. package/src/components/Calendar.tsx +284 -0
  16. package/src/components/CalendarAgenda.tsx +87 -0
  17. package/src/components/CalendarMonth.tsx +223 -0
  18. package/src/components/CalendarSchedule.tsx +210 -0
  19. package/src/components/Card.tsx +80 -0
  20. package/src/components/Charts.tsx +64 -0
  21. package/src/components/Chat.tsx +35 -0
  22. package/src/components/CitySelector.tsx +81 -0
  23. package/src/components/Clock.tsx +196 -0
  24. package/src/components/CodeInput.tsx +183 -0
  25. package/src/components/Container.tsx +20 -0
  26. package/src/components/Content.tsx +50 -0
  27. package/src/components/Data.tsx +43 -0
  28. package/src/components/DataInput.tsx +107 -0
  29. package/src/components/DateField.tsx +162 -0
  30. package/src/components/DonutChart.tsx +123 -0
  31. package/src/components/Drawer.tsx +110 -0
  32. package/src/components/Feedback.tsx +37 -0
  33. package/src/components/FileUploader.tsx +377 -0
  34. package/src/components/FunnelChart.tsx +83 -0
  35. package/src/components/Glyph.tsx +330 -0
  36. package/src/components/GoogleSignIn.tsx +67 -0
  37. package/src/components/GridSystem.tsx +131 -0
  38. package/src/components/HeatmapCalendar.tsx +167 -0
  39. package/src/components/KanbanBoard.tsx +421 -0
  40. package/src/components/Kpi.tsx +61 -0
  41. package/src/components/LayoutPrimitives.tsx +86 -0
  42. package/src/components/Lists.tsx +19 -0
  43. package/src/components/LocationSelector.tsx +49 -0
  44. package/src/components/MessageList.tsx +80 -0
  45. package/src/components/Nav.tsx +69 -0
  46. package/src/components/Navigation.tsx +52 -0
  47. package/src/components/Notification.tsx +115 -0
  48. package/src/components/NotificationTrigger.tsx +248 -0
  49. package/src/components/Overlay.tsx +50 -0
  50. package/src/components/Page.tsx +143 -0
  51. package/src/components/PageTabs.tsx +28 -0
  52. package/src/components/PickerShell.tsx +138 -0
  53. package/src/components/PillNav.tsx +194 -0
  54. package/src/components/Primitives.tsx +30 -0
  55. package/src/components/Rating.tsx +78 -0
  56. package/src/components/Responsive.tsx +128 -0
  57. package/src/components/ResponsiveFrame.tsx +122 -0
  58. package/src/components/Segment.tsx +190 -0
  59. package/src/components/Sparkline.tsx +52 -0
  60. package/src/components/StateSelector.tsx +39 -0
  61. package/src/components/Sticky.tsx +95 -0
  62. package/src/components/Table.tsx +344 -0
  63. package/src/components/ThemeToggle.tsx +48 -0
  64. package/src/components/Tile.tsx +23 -0
  65. package/src/components/TimeColumns.tsx +155 -0
  66. package/src/components/TimeDial.tsx +260 -0
  67. package/src/components/TimeField.tsx +196 -0
  68. package/src/components/TimeInput.tsx +213 -0
  69. package/src/components/TimeSlots.tsx +83 -0
  70. package/src/components/Timeline.tsx +111 -0
  71. package/src/components/TokenDemo.tsx +378 -0
  72. package/src/components/Tree.tsx +283 -0
  73. package/src/components/TrendChart.tsx +211 -0
  74. package/src/components/breakpoints.ts +42 -0
  75. package/src/components/calendarTypes.ts +26 -0
  76. package/src/components/chartMath.ts +125 -0
  77. package/src/components/chartParts.tsx +116 -0
  78. package/src/components/codeInputRules.ts +58 -0
  79. package/src/components/date.ts +87 -0
  80. package/src/components/hooks.ts +53 -0
  81. package/src/components/index.ts +195 -0
  82. package/src/components/kanban.ts +78 -0
  83. package/src/components/motion.ts +78 -0
  84. package/src/components/places-search.tsx +73 -0
  85. package/src/components/places.ts +209 -0
  86. package/src/components/size.ts +3 -0
  87. package/src/components/time.ts +83 -0
  88. package/src/components/useFileDrop.ts +104 -0
  89. package/src/places/geoapify.ts +129 -0
  90. package/src/styles/astryx.css +5 -0
  91. package/src/styles/components/brand.css +98 -0
  92. package/src/styles/components/calendar.css +680 -0
  93. package/src/styles/components/charts.css +659 -0
  94. package/src/styles/components/code-input.css +233 -0
  95. package/src/styles/components/google.css +11 -0
  96. package/src/styles/components/message-list.css +153 -0
  97. package/src/styles/components/notification.css +350 -0
  98. package/src/styles/components/picker.css +114 -0
  99. package/src/styles/components/pill-nav.css +179 -0
  100. package/src/styles/components/responsive.css +419 -0
  101. package/src/styles/components/sticky.css +23 -0
  102. package/src/styles/components/table.css +267 -0
  103. package/src/styles/components/time.css +526 -0
  104. package/src/styles/components/timeline.css +426 -0
  105. package/src/styles/components/tree.css +269 -0
  106. package/src/styles/components.css +423 -0
  107. package/src/styles/joined.css +4 -0
  108. package/src/styles/theme.css +79 -0
  109. package/src/styles/tokens.css +338 -0
  110. package/src/theme/JoinedProvider.tsx +50 -0
  111. package/src/theme/index.ts +3 -0
  112. package/src/theme/joined.d.ts +11 -0
  113. package/src/theme/joined.js +569 -0
  114. package/src/theme/joined.theme.ts +74 -0
  115. package/src/theme/joined.variants.d.ts +16 -0
  116. package/src/theme/theme.css +786 -0
@@ -0,0 +1,196 @@
1
+ "use client";
2
+
3
+ import { useNow } from "./hooks";
4
+ import {
5
+ HOURS_PER_HALF,
6
+ MINUTES_PER_HOUR,
7
+ SECONDS_PER_MINUTE,
8
+ meridiemOf,
9
+ pad2,
10
+ parseTime,
11
+ to12,
12
+ type HourCycle,
13
+ type TimeParts,
14
+ } from "./time";
15
+
16
+ import type { ControlSize } from "./size";
17
+
18
+ /**
19
+ * analog — numerals, minute ticks, three hands.
20
+ * minimal — twelve marks and two hands; calm enough for a sidebar.
21
+ * digital — large tabular digits with a quiet caption.
22
+ * compact — an inline pill for rows and headers.
23
+ */
24
+ export type ClockVariant = "analog" | "minimal" | "digital" | "compact";
25
+
26
+ export interface ClockProps {
27
+ /** A fixed "HH:mm[:ss]". Omit it for a live clock. */
28
+ value?: string;
29
+ variant?: ClockVariant;
30
+ size?: ControlSize;
31
+ hourCycle?: HourCycle;
32
+ showSeconds?: boolean;
33
+ /** IANA zone for a live clock, e.g. "Asia/Tokyo". Defaults to the viewer's. */
34
+ timeZone?: string;
35
+ /** Caption — a city, a room, a person. */
36
+ label?: string;
37
+ }
38
+
39
+ const TICK_MS = 1000;
40
+ const DEGREES = 360;
41
+ const NUMERALS = [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
42
+ const NUMERAL_RADIUS = 32;
43
+
44
+ function zoned(now: Date, timeZone?: string): TimeParts {
45
+ if (!timeZone) return { h: now.getHours(), m: now.getMinutes(), s: now.getSeconds() };
46
+ const pieces = new Intl.DateTimeFormat("en-US", {
47
+ timeZone,
48
+ hour: "numeric",
49
+ minute: "numeric",
50
+ second: "numeric",
51
+ hourCycle: "h23",
52
+ }).formatToParts(now);
53
+ const read = (type: string) => Number(pieces.find((piece) => piece.type === type)?.value ?? 0);
54
+ return { h: read("hour"), m: read("minute"), s: read("second") };
55
+ }
56
+
57
+ function Hand({ turn, length, className }: { turn: number; length: number; className: string }) {
58
+ return (
59
+ <line
60
+ className={className}
61
+ x1="50"
62
+ y1="50"
63
+ x2="50"
64
+ y2={50 - length}
65
+ style={{ transform: `rotate(${turn}deg)` }}
66
+ />
67
+ );
68
+ }
69
+
70
+ function Face({
71
+ parts,
72
+ variant,
73
+ showSeconds,
74
+ }: {
75
+ parts: TimeParts;
76
+ variant: "analog" | "minimal";
77
+ showSeconds: boolean;
78
+ }) {
79
+ const minuteTurn = (parts.m + parts.s / SECONDS_PER_MINUTE) * (DEGREES / MINUTES_PER_HOUR);
80
+ const hourTurn =
81
+ ((parts.h % HOURS_PER_HALF) + parts.m / MINUTES_PER_HOUR) * (DEGREES / HOURS_PER_HALF);
82
+ const secondTurn = parts.s * (DEGREES / SECONDS_PER_MINUTE);
83
+ const marks = variant === "analog" ? MINUTES_PER_HOUR : HOURS_PER_HALF;
84
+
85
+ return (
86
+ <svg className="os-clock-face" viewBox="0 0 100 100" aria-hidden>
87
+ <circle className="os-clock-rim" cx="50" cy="50" r="48" />
88
+ {Array.from({ length: marks }, (_, i) => {
89
+ const major = i % (marks / HOURS_PER_HALF) === 0;
90
+ return (
91
+ <line
92
+ key={i}
93
+ className={major ? "os-clock-mark os-clock-mark-major" : "os-clock-mark"}
94
+ x1="50"
95
+ y1={major ? 6 : 6.5}
96
+ x2="50"
97
+ y2={major ? 10 : 8}
98
+ style={{ transform: `rotate(${(i * DEGREES) / marks}deg)` }}
99
+ />
100
+ );
101
+ })}
102
+ {variant === "analog" &&
103
+ NUMERALS.map((n, i) => {
104
+ const angle = (i / HOURS_PER_HALF) * Math.PI * 2 - Math.PI / 2;
105
+ return (
106
+ <text
107
+ key={n}
108
+ className="os-clock-numeral"
109
+ x={50 + NUMERAL_RADIUS * Math.cos(angle)}
110
+ y={50 + NUMERAL_RADIUS * Math.sin(angle)}
111
+ >
112
+ {n}
113
+ </text>
114
+ );
115
+ })}
116
+ <Hand className="os-clock-hour" turn={hourTurn} length={variant === "analog" ? 19 : 22} />
117
+ <Hand className="os-clock-minute" turn={minuteTurn} length={variant === "analog" ? 29 : 33} />
118
+ {showSeconds && <Hand className="os-clock-second" turn={secondTurn} length={36} />}
119
+ <circle className="os-clock-pin" cx="50" cy="50" r="2" />
120
+ </svg>
121
+ );
122
+ }
123
+
124
+ /** Shows a time — fixed or live — in four treatments. It never takes input. */
125
+ export function Clock({
126
+ value,
127
+ variant = "analog",
128
+ size = "md",
129
+ hourCycle = "12h",
130
+ showSeconds = true,
131
+ timeZone,
132
+ label,
133
+ }: ClockProps) {
134
+ const now = useNow(TICK_MS, value === undefined);
135
+ const parts = value !== undefined ? parseTime(value) : now ? zoned(now, timeZone) : null;
136
+ const twelve = hourCycle === "12h";
137
+ const hour = parts ? (twelve ? String(to12(parts.h)) : pad2(parts.h)) : "--";
138
+ const minute = parts ? pad2(parts.m) : "--";
139
+ const second = parts ? pad2(parts.s) : "--";
140
+ const meridiem = parts && twelve ? meridiemOf(parts.h) : "";
141
+ const spoken = parts ? `${hour}:${minute}${meridiem ? ` ${meridiem}` : ""}` : "Loading time";
142
+ const root = [
143
+ "os-clock",
144
+ `os-clock-${variant}`,
145
+ `os-clock-${size}`,
146
+ value === undefined && "os-clock-live",
147
+ ]
148
+ .filter(Boolean)
149
+ .join(" ");
150
+
151
+ if (variant === "compact") {
152
+ return (
153
+ <span className={root} role="timer" aria-label={label ? `${label}, ${spoken}` : spoken}>
154
+ <span className="os-clock-pulse" aria-hidden />
155
+ <span className="os-clock-digits">
156
+ {hour}:{minute}
157
+ {meridiem && <span className="os-clock-meridiem"> {meridiem}</span>}
158
+ </span>
159
+ {label && <span className="os-clock-label">{label}</span>}
160
+ </span>
161
+ );
162
+ }
163
+
164
+ if (variant === "digital") {
165
+ return (
166
+ <div className={root} role="timer" aria-label={label ? `${label}, ${spoken}` : spoken}>
167
+ <div className="os-clock-digits" aria-hidden>
168
+ <span>{hour}</span>
169
+ <span className="os-clock-colon">:</span>
170
+ <span>{minute}</span>
171
+ <span className="os-clock-tail">
172
+ {meridiem && <span className="os-clock-meridiem">{meridiem}</span>}
173
+ {showSeconds && <span className="os-clock-seconds">{second}</span>}
174
+ </span>
175
+ </div>
176
+ {label && <span className="os-clock-label">{label}</span>}
177
+ </div>
178
+ );
179
+ }
180
+
181
+ return (
182
+ <figure className={root} role="timer" aria-label={label ? `${label}, ${spoken}` : spoken}>
183
+ {parts ? (
184
+ <Face parts={parts} variant={variant} showSeconds={showSeconds} />
185
+ ) : (
186
+ <span className="os-clock-face os-clock-face-empty" />
187
+ )}
188
+ {label && (
189
+ <figcaption className="os-clock-caption">
190
+ <span className="os-clock-label">{label}</span>
191
+ <span className="os-clock-small">{spoken}</span>
192
+ </figcaption>
193
+ )}
194
+ </figure>
195
+ );
196
+ }
@@ -0,0 +1,183 @@
1
+ "use client";
2
+
3
+ import {
4
+ useId,
5
+ useRef,
6
+ type ClipboardEvent,
7
+ type ChangeEvent,
8
+ type CSSProperties,
9
+ type KeyboardEvent,
10
+ } from "react";
11
+
12
+ import {
13
+ deleteCode,
14
+ insertCode,
15
+ typedCharacters,
16
+ type CodeCharset,
17
+ type CodeEdit,
18
+ } from "./codeInputRules";
19
+
20
+ import type { ControlSize } from "./size";
21
+
22
+ export const CODE_INPUT_LENGTH = 6;
23
+
24
+ export type CodeInputStatus = "default" | "error" | "success";
25
+
26
+ export interface CodeInputProps {
27
+ value: string;
28
+ onChange: (value: string) => void;
29
+ /** Called once, when the last cell is filled. */
30
+ onComplete?: (value: string) => void;
31
+ length?: number;
32
+ /** Digits only by default; `alphanumeric` also accepts letters (shown upper-case). */
33
+ charset?: CodeCharset;
34
+ label: string;
35
+ isLabelHidden?: boolean;
36
+ description?: string;
37
+ /** `error` shakes the cells once and turns them red; `success` ripples green across them. */
38
+ status?: CodeInputStatus;
39
+ isDisabled?: boolean;
40
+ hasAutoFocus?: boolean;
41
+ size?: ControlSize;
42
+ }
43
+
44
+ /** One round cell per character. Typing, pasting, backspace, and arrow keys move between cells. */
45
+ export function CodeInput({
46
+ value,
47
+ onChange,
48
+ onComplete,
49
+ length = CODE_INPUT_LENGTH,
50
+ charset = "numeric",
51
+ label,
52
+ isLabelHidden = false,
53
+ description,
54
+ status = "default",
55
+ isDisabled = false,
56
+ hasAutoFocus = false,
57
+ size = "md",
58
+ }: CodeInputProps) {
59
+ const id = useId();
60
+ const cells = useRef<Array<HTMLInputElement | null>>([]);
61
+ // Focus moves before React re-renders, so handlers read the newest value from here.
62
+ const latest = useRef(value);
63
+ latest.current = value;
64
+
65
+ const focusCell = (index: number) => {
66
+ const cell = cells.current[Math.max(0, Math.min(index, length - 1))];
67
+ cell?.focus();
68
+ cell?.select();
69
+ };
70
+
71
+ const apply = ({ value: next, focusIndex }: CodeEdit) => {
72
+ if (next !== latest.current) {
73
+ latest.current = next;
74
+ onChange(next);
75
+ if (next.length === length) onComplete?.(next);
76
+ }
77
+ focusCell(focusIndex);
78
+ };
79
+
80
+ const handleChange = (index: number, event: ChangeEvent<HTMLInputElement>) => {
81
+ const current = latest.current;
82
+ const typed = typedCharacters(event.target.value, current[index]);
83
+ if (!typed) {
84
+ apply(deleteCode(current, index));
85
+ return;
86
+ }
87
+ apply(insertCode(current, index, typed, length, charset));
88
+ };
89
+
90
+ const handleKeyDown = (index: number, event: KeyboardEvent<HTMLInputElement>) => {
91
+ const current = latest.current;
92
+ switch (event.key) {
93
+ case "Backspace":
94
+ event.preventDefault();
95
+ apply(deleteCode(current, index));
96
+ break;
97
+ case "Delete":
98
+ event.preventDefault();
99
+ if (index < current.length) apply(deleteCode(current, index));
100
+ break;
101
+ case "ArrowLeft":
102
+ event.preventDefault();
103
+ focusCell(index - 1);
104
+ break;
105
+ case "ArrowRight":
106
+ event.preventDefault();
107
+ focusCell(Math.min(index + 1, current.length));
108
+ break;
109
+ case "Home":
110
+ event.preventDefault();
111
+ focusCell(0);
112
+ break;
113
+ case "End":
114
+ event.preventDefault();
115
+ focusCell(current.length);
116
+ break;
117
+ }
118
+ };
119
+
120
+ const handlePaste = (index: number, event: ClipboardEvent<HTMLInputElement>) => {
121
+ event.preventDefault();
122
+ apply(insertCode(latest.current, index, event.clipboardData.getData("text"), length, charset));
123
+ };
124
+
125
+ return (
126
+ <div
127
+ className={`os-code os-code-${size}`}
128
+ role="group"
129
+ aria-labelledby={`${id}-label`}
130
+ aria-describedby={description ? `${id}-description` : undefined}
131
+ data-status={status}
132
+ >
133
+ <span
134
+ id={`${id}-label`}
135
+ className={isLabelHidden ? "os-code-label os-code-label-hidden" : "os-code-label"}
136
+ >
137
+ {label}
138
+ </span>
139
+ <div className="os-code-cells">
140
+ {Array.from({ length }, (_, index) => {
141
+ const character = value[index] ?? "";
142
+ return (
143
+ <div
144
+ key={index}
145
+ className="os-code-cell"
146
+ data-filled={character ? "true" : "false"}
147
+ style={{ "--os-code-index": index } as CSSProperties}
148
+ >
149
+ <input
150
+ ref={(node) => {
151
+ cells.current[index] = node;
152
+ }}
153
+ className="os-code-input"
154
+ value={character}
155
+ onChange={(event) => handleChange(index, event)}
156
+ onKeyDown={(event) => handleKeyDown(index, event)}
157
+ onPaste={(event) => handlePaste(index, event)}
158
+ onFocus={(event) => {
159
+ // Reaching a cell past the end lands on the first empty one.
160
+ if (index > latest.current.length) focusCell(latest.current.length);
161
+ else event.target.select();
162
+ }}
163
+ inputMode={charset === "numeric" ? "numeric" : "text"}
164
+ autoComplete="one-time-code"
165
+ autoCapitalize="characters"
166
+ spellCheck={false}
167
+ aria-label={`${label}, character ${index + 1} of ${length}`}
168
+ aria-invalid={status === "error" || undefined}
169
+ disabled={isDisabled}
170
+ autoFocus={hasAutoFocus && index === 0}
171
+ />
172
+ </div>
173
+ );
174
+ })}
175
+ </div>
176
+ {description ? (
177
+ <span id={`${id}-description`} className="os-code-description">
178
+ {description}
179
+ </span>
180
+ ) : null}
181
+ </div>
182
+ );
183
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Containers are original Astryx — Joined only themes them. Card itself
3
+ * lives in ./Primitives; JobCard composes these for the Joined room card.
4
+ */
5
+ export { ClickableCard } from "@astryxdesign/core/ClickableCard";
6
+ export type { ClickableCardProps } from "@astryxdesign/core/ClickableCard";
7
+
8
+ export { SelectableCard } from "@astryxdesign/core/SelectableCard";
9
+ export type { SelectableCardProps } from "@astryxdesign/core/SelectableCard";
10
+
11
+ export { Carousel } from "@astryxdesign/core/Carousel";
12
+ export type { CarouselProps, CarouselHandle } from "@astryxdesign/core/Carousel";
13
+
14
+ export { Collapsible, CollapsibleGroup, useCollapsible } from "@astryxdesign/core/Collapsible";
15
+ export type {
16
+ CollapsibleProps,
17
+ CollapsibleGroupProps,
18
+ CollapsibleChevronPosition,
19
+ CollapsibleGroupDensity,
20
+ } from "@astryxdesign/core/Collapsible";
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Content components are original Astryx — Joined only themes them.
3
+ * Text, Heading, and Icon live in ./Primitives; import everything from
4
+ * sid-ui so apps never reach into Astryx directly.
5
+ */
6
+ export { Avatar, AvatarStatusDot } from "@astryxdesign/core/Avatar";
7
+ export type {
8
+ AvatarProps,
9
+ AvatarSize,
10
+ AvatarShape,
11
+ AvatarStatusDotProps,
12
+ AvatarStatusDotVariant,
13
+ } from "@astryxdesign/core/Avatar";
14
+
15
+ export { AvatarGroup, AvatarGroupOverflow } from "@astryxdesign/core/AvatarGroup";
16
+ export type { AvatarGroupProps, AvatarGroupOverflowProps } from "@astryxdesign/core/AvatarGroup";
17
+
18
+ export { Blockquote } from "@astryxdesign/core/Blockquote";
19
+ export type { BlockquoteProps } from "@astryxdesign/core/Blockquote";
20
+
21
+ export { Citation } from "@astryxdesign/core/Citation";
22
+ export type { CitationProps, CitationSource } from "@astryxdesign/core/Citation";
23
+
24
+ export { Code } from "@astryxdesign/core/Code";
25
+ export type { CodeProps, CodeColor, CodeSize } from "@astryxdesign/core/Code";
26
+
27
+ export { CodeBlock } from "@astryxdesign/core/CodeBlock";
28
+ export type { CodeBlockProps } from "@astryxdesign/core/CodeBlock";
29
+
30
+ export { EmptyState } from "@astryxdesign/core/EmptyState";
31
+ export type { EmptyStateProps } from "@astryxdesign/core/EmptyState";
32
+
33
+ export { Kbd } from "@astryxdesign/core/Kbd";
34
+ export type { KbdProps } from "@astryxdesign/core/Kbd";
35
+
36
+ export { Markdown } from "@astryxdesign/core/Markdown";
37
+ export type { MarkdownProps, MarkdownSource } from "@astryxdesign/core/Markdown";
38
+
39
+ export { Thumbnail } from "@astryxdesign/core/Thumbnail";
40
+ export type { ThumbnailProps } from "@astryxdesign/core/Thumbnail";
41
+
42
+ export { Timestamp } from "@astryxdesign/core/Timestamp";
43
+ export type {
44
+ TimestampProps,
45
+ TimestampFormat,
46
+ TimestampTooltipEntry,
47
+ } from "@astryxdesign/core/Timestamp";
48
+
49
+ export { Token } from "@astryxdesign/core/Token";
50
+ export type { TokenProps, TokenColor, TokenSize } from "@astryxdesign/core/Token";
@@ -0,0 +1,43 @@
1
+ "use client";
2
+
3
+ import { Tree, type TreeNode } from "./Tree";
4
+
5
+ import type { ReactNode } from "react";
6
+
7
+ /** The two-level shorthand for Tree — every branch starts open. */
8
+ export function TreeList({
9
+ items,
10
+ }: {
11
+ items: { label: string; children?: { label: string }[] }[];
12
+ }) {
13
+ const nodes: TreeNode[] = items.map((item) => ({
14
+ id: item.label,
15
+ label: item.label,
16
+ children: item.children?.map((child) => ({
17
+ id: `${item.label}/${child.label}`,
18
+ label: child.label,
19
+ })),
20
+ }));
21
+ return <Tree nodes={nodes} variant="guides" defaultExpanded={nodes.map((node) => node.id)} />;
22
+ }
23
+
24
+ export function PageBody({ children, className }: { children: ReactNode; className?: string }) {
25
+ return <div className={className ? `os-page-body ${className}` : "os-page-body"}>{children}</div>;
26
+ }
27
+
28
+ export function PageHero({ children }: { children: ReactNode }) {
29
+ return <div className="os-page-hero">{children}</div>;
30
+ }
31
+
32
+ export function Preview({ label, children }: { label?: string; children: ReactNode }) {
33
+ return (
34
+ <div className="os-preview">
35
+ <div className="os-preview-stage">{children}</div>
36
+ {label && <p className="caption os-preview-label">{label}</p>}
37
+ </div>
38
+ );
39
+ }
40
+
41
+ export function PreviewGrid({ children }: { children: ReactNode }) {
42
+ return <div className="os-preview-grid">{children}</div>;
43
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Data input controls are original Astryx — Joined only themes them.
3
+ * Joined's own pickers (Calendar, DateField, TimeInput, Clock) and Rating
4
+ * live beside these; import everything from sid-ui.
5
+ */
6
+ export { Field, FieldLabel, FieldStatus } from "@astryxdesign/core/Field";
7
+ export type {
8
+ FieldProps,
9
+ FieldLabelProps,
10
+ FieldStatusProps,
11
+ FieldStatusVariant,
12
+ InputStatus,
13
+ InputStatusType,
14
+ } from "@astryxdesign/core/Field";
15
+
16
+ export { TextInput } from "@astryxdesign/core/TextInput";
17
+ export type { TextInputProps, TextInputType, TextInputSize } from "@astryxdesign/core/TextInput";
18
+
19
+ export { TextArea } from "@astryxdesign/core/TextArea";
20
+ export type { TextAreaProps, TextAreaSize } from "@astryxdesign/core/TextArea";
21
+
22
+ export { NumberInput } from "@astryxdesign/core/NumberInput";
23
+ export type { NumberInputProps, NumberInputSize } from "@astryxdesign/core/NumberInput";
24
+
25
+ export { InputGroup, InputGroupText } from "@astryxdesign/core/InputGroup";
26
+ export type {
27
+ InputGroupProps,
28
+ InputGroupSize,
29
+ InputGroupTextProps,
30
+ } from "@astryxdesign/core/InputGroup";
31
+
32
+ export { CheckboxInput } from "@astryxdesign/core/CheckboxInput";
33
+ export type { CheckboxInputProps, CheckboxInputSize } from "@astryxdesign/core/CheckboxInput";
34
+
35
+ export { CheckboxList, CheckboxListItem } from "@astryxdesign/core/CheckboxList";
36
+ export type { CheckboxListProps, CheckboxListItemProps } from "@astryxdesign/core/CheckboxList";
37
+
38
+ export { RadioList, RadioListItem } from "@astryxdesign/core/RadioList";
39
+ export type {
40
+ RadioListProps,
41
+ RadioListItemProps,
42
+ RadioListSize,
43
+ } from "@astryxdesign/core/RadioList";
44
+
45
+ export { Switch } from "@astryxdesign/core/Switch";
46
+ export type {
47
+ SwitchProps,
48
+ SwitchLabelPosition,
49
+ SwitchLabelSpacing,
50
+ } from "@astryxdesign/core/Switch";
51
+
52
+ export { Slider } from "@astryxdesign/core/Slider";
53
+ export type { SliderProps, SliderSingleProps, SliderRangeProps } from "@astryxdesign/core/Slider";
54
+
55
+ export { Selector } from "@astryxdesign/core/Selector";
56
+ export type {
57
+ SelectorProps,
58
+ SelectorSize,
59
+ SelectorOptionData,
60
+ SelectorSection,
61
+ SelectorDivider,
62
+ } from "@astryxdesign/core/Selector";
63
+
64
+ export { MultiSelector } from "@astryxdesign/core/MultiSelector";
65
+ export type {
66
+ MultiSelectorProps,
67
+ MultiSelectorSize,
68
+ MultiSelectorOptionData,
69
+ MultiSelectorSection,
70
+ } from "@astryxdesign/core/MultiSelector";
71
+
72
+ export { DateInput } from "@astryxdesign/core/DateInput";
73
+ export type { DateInputProps, DateInputSize, DateInputFormat } from "@astryxdesign/core/DateInput";
74
+ export type { ISODateString, DayOfWeekName } from "@astryxdesign/core/Calendar";
75
+
76
+ export { DateRangeInput } from "@astryxdesign/core/DateRangeInput";
77
+ export type {
78
+ DateRangeInputProps,
79
+ DateRangePreset,
80
+ DateRange as DateRangeValue,
81
+ } from "@astryxdesign/core/DateRangeInput";
82
+
83
+ export { DateTimeInput } from "@astryxdesign/core/DateTimeInput";
84
+ export type {
85
+ DateTimeInputProps,
86
+ DateTimeInputHourFormat,
87
+ ISODateTimeString,
88
+ } from "@astryxdesign/core/DateTimeInput";
89
+
90
+ export { FileInput } from "@astryxdesign/core/FileInput";
91
+ export type { FileInputProps } from "@astryxdesign/core/FileInput";
92
+
93
+ export { Typeahead, TypeaheadItem, createStaticSource } from "@astryxdesign/core/Typeahead";
94
+ export type {
95
+ TypeaheadProps,
96
+ TypeaheadItemProps,
97
+ SearchableItem,
98
+ SearchSource,
99
+ } from "@astryxdesign/core/Typeahead";
100
+
101
+ export { Tokenizer } from "@astryxdesign/core/Tokenizer";
102
+ export type {
103
+ TokenizerProps,
104
+ TokenizerSize,
105
+ TokenizerChange,
106
+ TokenizerOverflowBehavior,
107
+ } from "@astryxdesign/core/Tokenizer";