terminoir 0.4.0 → 0.5.1

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 (98) hide show
  1. package/README.md +38 -28
  2. package/css/components.css +62 -0
  3. package/css/shell.css +32 -1
  4. package/dist/components/AccentSwatches.svelte +1 -1
  5. package/dist/components/AppShell.svelte +33 -5
  6. package/dist/components/AppShell.svelte.d.ts +10 -1
  7. package/dist/components/AppShellNavLink.svelte +2 -4
  8. package/dist/components/Button.svelte +32 -14
  9. package/dist/components/Button.svelte.d.ts +2 -0
  10. package/dist/components/CalendarGrid.svelte +260 -0
  11. package/dist/components/CalendarGrid.svelte.d.ts +12 -0
  12. package/dist/components/CanvasStage.svelte +81 -0
  13. package/dist/components/CanvasStage.svelte.d.ts +19 -0
  14. package/dist/components/Centered.svelte +36 -0
  15. package/dist/components/Centered.svelte.d.ts +10 -0
  16. package/dist/components/Checkbox.svelte +64 -12
  17. package/dist/components/Checkbox.svelte.d.ts +5 -0
  18. package/dist/components/Chip.svelte +90 -2
  19. package/dist/components/Chip.svelte.d.ts +8 -0
  20. package/dist/components/CommandPalette.svelte +178 -97
  21. package/dist/components/CommandPalette.svelte.d.ts +15 -8
  22. package/dist/components/ContextMenu.svelte +68 -0
  23. package/dist/components/ContextMenu.svelte.d.ts +12 -0
  24. package/dist/components/DataTable.svelte +139 -0
  25. package/dist/components/DataTable.svelte.d.ts +39 -0
  26. package/dist/components/DescriptionList.svelte +41 -0
  27. package/dist/components/DescriptionList.svelte.d.ts +8 -0
  28. package/dist/components/Dialog.svelte +17 -8
  29. package/dist/components/Disclosure.svelte +55 -0
  30. package/dist/components/Disclosure.svelte.d.ts +10 -0
  31. package/dist/components/DocumentViewer.svelte +105 -0
  32. package/dist/components/DocumentViewer.svelte.d.ts +23 -0
  33. package/dist/components/Drawer.svelte +119 -0
  34. package/dist/components/Drawer.svelte.d.ts +16 -0
  35. package/dist/components/DropdownMenu.svelte +46 -62
  36. package/dist/components/DropdownMenu.svelte.d.ts +7 -6
  37. package/dist/components/FieldMessage.svelte +9 -0
  38. package/dist/components/FieldMessage.svelte.d.ts +8 -0
  39. package/dist/components/FileButton.svelte +44 -0
  40. package/dist/components/FileButton.svelte.d.ts +16 -0
  41. package/dist/components/FormRow.svelte +62 -0
  42. package/dist/components/FormRow.svelte.d.ts +13 -0
  43. package/dist/components/IconField.svelte +80 -5
  44. package/dist/components/IconField.svelte.d.ts +2 -0
  45. package/dist/components/Inline.svelte +52 -0
  46. package/dist/components/Inline.svelte.d.ts +16 -0
  47. package/dist/components/Input.svelte +23 -3
  48. package/dist/components/Input.svelte.d.ts +9 -0
  49. package/dist/components/List.svelte +42 -0
  50. package/dist/components/List.svelte.d.ts +13 -0
  51. package/dist/components/ListItem.svelte +114 -0
  52. package/dist/components/ListItem.svelte.d.ts +17 -0
  53. package/dist/components/MenuItems.svelte +44 -0
  54. package/dist/components/MenuItems.svelte.d.ts +8 -0
  55. package/dist/components/NavSection.svelte +45 -0
  56. package/dist/components/NavSection.svelte.d.ts +12 -0
  57. package/dist/components/Page.svelte +53 -0
  58. package/dist/components/Page.svelte.d.ts +12 -0
  59. package/dist/components/PageHeader.svelte +91 -0
  60. package/dist/components/PageHeader.svelte.d.ts +15 -0
  61. package/dist/components/Prose.svelte +33 -0
  62. package/dist/components/Prose.svelte.d.ts +8 -0
  63. package/dist/components/RadioCards.svelte +68 -0
  64. package/dist/components/RadioCards.svelte.d.ts +11 -0
  65. package/dist/components/SearchPicker.svelte +171 -0
  66. package/dist/components/SearchPicker.svelte.d.ts +19 -0
  67. package/dist/components/Section.svelte +71 -0
  68. package/dist/components/Section.svelte.d.ts +12 -0
  69. package/dist/components/SegmentedControl.svelte +63 -0
  70. package/dist/components/SegmentedControl.svelte.d.ts +12 -0
  71. package/dist/components/Select.svelte +22 -4
  72. package/dist/components/Select.svelte.d.ts +9 -1
  73. package/dist/components/Spacer.svelte +6 -0
  74. package/dist/components/Spacer.svelte.d.ts +26 -0
  75. package/dist/components/Stack.svelte +37 -0
  76. package/dist/components/Stack.svelte.d.ts +12 -0
  77. package/dist/components/Switch.svelte +6 -2
  78. package/dist/components/Switch.svelte.d.ts +2 -0
  79. package/dist/components/Tabs.svelte +6 -4
  80. package/dist/components/Text.svelte +68 -0
  81. package/dist/components/Text.svelte.d.ts +15 -0
  82. package/dist/components/Textarea.svelte +19 -3
  83. package/dist/components/Textarea.svelte.d.ts +6 -0
  84. package/dist/components/TitleInput.svelte +62 -0
  85. package/dist/components/TitleInput.svelte.d.ts +10 -0
  86. package/dist/index.d.ts +35 -2
  87. package/dist/index.js +31 -0
  88. package/dist/utils/calendar.d.ts +48 -0
  89. package/dist/utils/calendar.js +105 -0
  90. package/dist/utils/commands.d.ts +22 -0
  91. package/dist/utils/commands.js +17 -0
  92. package/dist/utils/componentTypes.d.ts +41 -0
  93. package/dist/utils/componentTypes.js +1 -0
  94. package/dist/utils/listNav.d.ts +2 -0
  95. package/dist/utils/listNav.js +8 -0
  96. package/dist/utils/menu.d.ts +10 -0
  97. package/dist/utils/menu.js +1 -0
  98. package/package.json +5 -3
@@ -0,0 +1,105 @@
1
+ /** Wall-clock calendar helpers (local time zone) for week and month views. */
2
+ export const MINUTES_PER_DAY = 24 * 60;
3
+ const MIN_EVENT_MINUTES = 15;
4
+ const MONTH_GRID_DAYS = 42;
5
+ export function startOfDay(d) {
6
+ const x = new Date(d);
7
+ x.setHours(0, 0, 0, 0);
8
+ return x;
9
+ }
10
+ /** Monday of the week containing `d`. */
11
+ export function startOfWeek(d) {
12
+ const x = startOfDay(d);
13
+ const day = x.getDay();
14
+ x.setDate(x.getDate() + (day === 0 ? -6 : 1 - day));
15
+ return x;
16
+ }
17
+ export function addDays(d, n) {
18
+ const x = new Date(d);
19
+ x.setDate(x.getDate() + n);
20
+ return x;
21
+ }
22
+ export function sameDay(a, b) {
23
+ return startOfDay(a).getTime() === startOfDay(b).getTime();
24
+ }
25
+ /** Visible range `[start, end)` around `anchor`: a Monday-start week or a calendar month. */
26
+ export function calendarRange(anchor, mode) {
27
+ if (mode === 'week') {
28
+ const start = startOfWeek(anchor);
29
+ return { start, end: addDays(start, 7) };
30
+ }
31
+ return {
32
+ start: new Date(anchor.getFullYear(), anchor.getMonth(), 1),
33
+ end: new Date(anchor.getFullYear(), anchor.getMonth() + 1, 1),
34
+ };
35
+ }
36
+ /** Move the anchor by `delta` weeks or months. */
37
+ export function shiftCalendar(anchor, mode, delta) {
38
+ if (mode === 'week')
39
+ return addDays(anchor, 7 * delta);
40
+ const x = new Date(anchor);
41
+ x.setMonth(x.getMonth() + delta);
42
+ return x;
43
+ }
44
+ /** Six Monday-start weeks covering the month of `monthStart`. */
45
+ export function monthGrid(monthStart) {
46
+ const first = startOfWeek(monthStart);
47
+ return Array.from({ length: MONTH_GRID_DAYS }, (_, i) => addDays(first, i));
48
+ }
49
+ /** Whether `event` shows on `day`: timed events on their start day, all-day events on every day they span. */
50
+ function occursOn(event, day) {
51
+ if (!event.allDay)
52
+ return sameDay(event.start, day);
53
+ const dayStart = startOfDay(day).getTime();
54
+ const end = Math.max(event.end.getTime(), addDays(startOfDay(event.start), 1).getTime());
55
+ return startOfDay(event.start).getTime() <= dayStart && dayStart < end;
56
+ }
57
+ /** Events showing on `day` (multi-day all-day events on each day), all-day first, then by start time. */
58
+ export function eventsOn(events, day) {
59
+ return events
60
+ .filter((e) => occursOn(e, day))
61
+ .sort((a, b) => Number(b.allDay) - Number(a.allDay) || a.start.getTime() - b.start.getTime());
62
+ }
63
+ /** Vertical position of a timed event in a day column, as percentages of the day. */
64
+ export function dayLayout(event) {
65
+ const minutes = (event.start.getTime() - startOfDay(event.start).getTime()) / 60000;
66
+ const duration = Math.max(MIN_EVENT_MINUTES, (event.end.getTime() - event.start.getTime()) / 60000);
67
+ const top = (minutes / MINUTES_PER_DAY) * 100;
68
+ return { top, height: Math.min((duration / MINUTES_PER_DAY) * 100, 100 - top) };
69
+ }
70
+ const COMPACT_MAX_MINUTES = 30;
71
+ /** Lay out a day's timed events so overlapping ones sit side by side instead of on top of each other. */
72
+ export function layoutDay(events) {
73
+ const sorted = [...events].sort((a, b) => a.start.getTime() - b.start.getTime() || b.end.getTime() - a.end.getTime());
74
+ const placed = [];
75
+ let group = [];
76
+ let laneEnds = [];
77
+ let groupEnd = -Infinity;
78
+ const closeGroup = () => {
79
+ for (const item of group)
80
+ item.lanes = laneEnds.length;
81
+ group = [];
82
+ laneEnds = [];
83
+ };
84
+ for (const event of sorted) {
85
+ const start = event.start.getTime();
86
+ const end = Math.max(event.end.getTime(), start + MIN_EVENT_MINUTES * 60000);
87
+ if (start >= groupEnd)
88
+ closeGroup();
89
+ let lane = laneEnds.findIndex((laneEnd) => laneEnd <= start);
90
+ if (lane === -1) {
91
+ lane = laneEnds.length;
92
+ laneEnds.push(end);
93
+ }
94
+ else {
95
+ laneEnds[lane] = end;
96
+ }
97
+ groupEnd = Math.max(groupEnd, end);
98
+ const minutes = (event.end.getTime() - start) / 60000;
99
+ const item = { event, ...dayLayout(event), lane, lanes: 1, compact: minutes <= COMPACT_MAX_MINUTES };
100
+ group.push(item);
101
+ placed.push(item);
102
+ }
103
+ closeGroup();
104
+ return placed;
105
+ }
@@ -0,0 +1,22 @@
1
+ export type CommandItem = {
2
+ id: string;
3
+ label: string;
4
+ /** Secondary text on the right, e.g. a type name or shortcut. */
5
+ hint?: string;
6
+ /** Extra words that match the query but are not shown. */
7
+ keywords?: string;
8
+ /** Rows with the same group are listed together under that heading. */
9
+ group?: string;
10
+ /** NavIcon name shown before the label. */
11
+ icon?: string;
12
+ iconColor?: string;
13
+ onSelect?: () => void;
14
+ };
15
+ export type CommandGroup = {
16
+ group: string | undefined;
17
+ items: CommandItem[];
18
+ };
19
+ /** Case-insensitive substring match on label + keywords; an empty query keeps everything. */
20
+ export declare function filterCommands(items: CommandItem[], query: string): CommandItem[];
21
+ /** Group rows by `group`, keeping first-seen group order and row order within groups. */
22
+ export declare function groupCommands(items: CommandItem[]): CommandGroup[];
@@ -0,0 +1,17 @@
1
+ /** Case-insensitive substring match on label + keywords; an empty query keeps everything. */
2
+ export function filterCommands(items, query) {
3
+ const needle = query.trim().toLowerCase();
4
+ if (!needle)
5
+ return items;
6
+ return items.filter((item) => `${item.label} ${item.keywords ?? ''}`.toLowerCase().includes(needle));
7
+ }
8
+ /** Group rows by `group`, keeping first-seen group order and row order within groups. */
9
+ export function groupCommands(items) {
10
+ const groups = new Map();
11
+ for (const item of items) {
12
+ const rows = groups.get(item.group) ?? [];
13
+ rows.push(item);
14
+ groups.set(item.group, rows);
15
+ }
16
+ return [...groups].map(([group, rows]) => ({ group, items: rows }));
17
+ }
@@ -0,0 +1,41 @@
1
+ export type DataColumn = {
2
+ key: string;
3
+ label: string;
4
+ /** CSS width, e.g. `8rem` or `30%`. */
5
+ width?: string;
6
+ align?: 'start' | 'end';
7
+ /** Hide below 700px so phone tables keep their key columns. */
8
+ hideOnMobile?: boolean;
9
+ };
10
+ export type PickerOption = {
11
+ id: string;
12
+ label: string;
13
+ description?: string;
14
+ /** NavIcon name. */
15
+ icon?: string;
16
+ iconColor?: string;
17
+ };
18
+ export type RadioCardOption = {
19
+ value: string;
20
+ label: string;
21
+ description?: string;
22
+ };
23
+ export type SegmentOption = {
24
+ value: string;
25
+ label: string;
26
+ };
27
+ export type DescriptionItem = {
28
+ term: string;
29
+ detail: string | number;
30
+ tone?: 'default' | 'danger' | 'success';
31
+ };
32
+ export type ViewerMark = {
33
+ id: string;
34
+ /** Position and size as fractions (0–1) of the page. */
35
+ x: number;
36
+ y: number;
37
+ w: number;
38
+ h: number;
39
+ color?: string;
40
+ label?: string;
41
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ /** Move a highlighted row by `delta`, wrapping around a list of `length` rows (-1 when empty). */
2
+ export declare function moveIndex(current: number, delta: number, length: number): number;
@@ -0,0 +1,8 @@
1
+ /** Move a highlighted row by `delta`, wrapping around a list of `length` rows (-1 when empty). */
2
+ export function moveIndex(current, delta, length) {
3
+ if (length <= 0)
4
+ return -1;
5
+ if (current < 0)
6
+ return delta > 0 ? 0 : length - 1;
7
+ return (((current + delta) % length) + length) % length;
8
+ }
@@ -0,0 +1,10 @@
1
+ export type MenuItem = {
2
+ id: string;
3
+ label: string;
4
+ /** NavIcon name. */
5
+ icon?: string;
6
+ /** `danger` for destructive actions (delete, revoke). */
7
+ tone?: 'default' | 'danger';
8
+ disabled?: boolean;
9
+ onSelect?: () => void;
10
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "terminoir",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Terminoir \u2014 Liquid Glass design tokens and Svelte 5 UI components.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -55,11 +55,12 @@
55
55
  "test": "vitest run",
56
56
  "demo:dev": "pnpm --dir demo dev",
57
57
  "demo:build": "pnpm --dir demo build",
58
- "prepublishOnly": "pnpm build && pnpm test"
58
+ "prepublishOnly": "pnpm check && pnpm build && pnpm test",
59
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --threshold error"
59
60
  },
60
61
  "peerDependencies": {
61
62
  "react": ">=18 <20",
62
- "svelte": "^5.0.0"
63
+ "svelte": "^5.20.0"
63
64
  },
64
65
  "peerDependenciesMeta": {
65
66
  "react": {
@@ -96,6 +97,7 @@
96
97
  "publint": "^0.3.8",
97
98
  "react": "^19.0.0",
98
99
  "svelte": "^5.20.2",
100
+ "svelte-check": "^4.7.8",
99
101
  "tsup": "^8.3.5",
100
102
  "typescript": "^5.7.3",
101
103
  "vitest": "^3.0.5"