@riducms/admin 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 (226) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/THIRD_PARTY_NOTICES.md +217 -0
  4. package/package.json +62 -0
  5. package/src/app/admin-core-view-route.svelte +89 -0
  6. package/src/app/admin-layout.svelte +457 -0
  7. package/src/app/admin-navigation-progress.svelte +204 -0
  8. package/src/app/admin-page-title.svelte +94 -0
  9. package/src/app/admin-provider-layer.svelte +26 -0
  10. package/src/app/admin-router-root.svelte +9 -0
  11. package/src/app/admin-routes.svelte +116 -0
  12. package/src/app/deferred-redirect.svelte +23 -0
  13. package/src/app/loading-boundary.svelte +70 -0
  14. package/src/app/not-found-route.svelte +29 -0
  15. package/src/app-meta.ts +2 -0
  16. package/src/app.css +467 -0
  17. package/src/app.svelte +88 -0
  18. package/src/assets/ridu-logo-arch.svg +3 -0
  19. package/src/assets/ridu-word-logo.svg +7 -0
  20. package/src/components/brand/ridu-logo.svelte +24 -0
  21. package/src/components/code-block/code-block.svelte +107 -0
  22. package/src/components/json-tree/json-tree-node.svelte +77 -0
  23. package/src/components/json-tree/json-viewer.svelte +113 -0
  24. package/src/components/ui/banner/banner.svelte +41 -0
  25. package/src/components/ui/banner/index.ts +5 -0
  26. package/src/components/ui/bulk-action-bar/bulk-action-bar.svelte +50 -0
  27. package/src/components/ui/bulk-action-bar/index.ts +1 -0
  28. package/src/components/ui/button/index.ts +8 -0
  29. package/src/components/ui/calendar/calendar-caption.svelte +72 -0
  30. package/src/components/ui/calendar/calendar-cell.svelte +20 -0
  31. package/src/components/ui/calendar/calendar-day.svelte +27 -0
  32. package/src/components/ui/calendar/calendar-grid-row.svelte +13 -0
  33. package/src/components/ui/calendar/calendar-grid.svelte +17 -0
  34. package/src/components/ui/calendar/calendar-head-cell.svelte +20 -0
  35. package/src/components/ui/calendar/calendar-header.svelte +20 -0
  36. package/src/components/ui/calendar/calendar-heading.svelte +17 -0
  37. package/src/components/ui/calendar/calendar-month-select.svelte +45 -0
  38. package/src/components/ui/calendar/calendar-month.svelte +16 -0
  39. package/src/components/ui/calendar/calendar-months.svelte +20 -0
  40. package/src/components/ui/calendar/calendar-nav.svelte +20 -0
  41. package/src/components/ui/calendar/calendar-next-button.svelte +30 -0
  42. package/src/components/ui/calendar/calendar-prev-button.svelte +30 -0
  43. package/src/components/ui/calendar/calendar-year-select.svelte +44 -0
  44. package/src/components/ui/calendar/calendar.svelte +118 -0
  45. package/src/components/ui/calendar/index.ts +1 -0
  46. package/src/components/ui/checkbox/checkbox.svelte +35 -0
  47. package/src/components/ui/checkbox/index.ts +1 -0
  48. package/src/components/ui/confirmation-dialog/confirmation-dialog.svelte +37 -0
  49. package/src/components/ui/confirmation-dialog/index.ts +1 -0
  50. package/src/components/ui/date-value-control/date-value-calendar.svelte +37 -0
  51. package/src/components/ui/date-value-control/date-value-control-loader.svelte +36 -0
  52. package/src/components/ui/date-value-control/date-value-control.svelte +177 -0
  53. package/src/components/ui/date-value-control/index.ts +3 -0
  54. package/src/components/ui/dialog/dialog-close.svelte +11 -0
  55. package/src/components/ui/dialog/dialog-content.svelte +52 -0
  56. package/src/components/ui/dialog/dialog-description.svelte +20 -0
  57. package/src/components/ui/dialog/dialog-footer.svelte +20 -0
  58. package/src/components/ui/dialog/dialog-header.svelte +20 -0
  59. package/src/components/ui/dialog/dialog-overlay.svelte +20 -0
  60. package/src/components/ui/dialog/dialog-title.svelte +17 -0
  61. package/src/components/ui/dialog/dialog-trigger.svelte +11 -0
  62. package/src/components/ui/dialog/dialog.svelte +7 -0
  63. package/src/components/ui/dialog/index.ts +8 -0
  64. package/src/components/ui/dropdown-menu/dropdown-menu-content.svelte +27 -0
  65. package/src/components/ui/dropdown-menu/dropdown-menu-item.svelte +20 -0
  66. package/src/components/ui/dropdown-menu/dropdown-menu-separator.svelte +17 -0
  67. package/src/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +16 -0
  68. package/src/components/ui/dropdown-menu/dropdown-menu.svelte +7 -0
  69. package/src/components/ui/dropdown-menu/index.ts +5 -0
  70. package/src/components/ui/empty-state/empty-state.svelte +34 -0
  71. package/src/components/ui/empty-state/index.ts +1 -0
  72. package/src/components/ui/input/index.ts +1 -0
  73. package/src/components/ui/kbd/index.ts +1 -0
  74. package/src/components/ui/kbd/kbd.svelte +24 -0
  75. package/src/components/ui/pagination/index.ts +1 -0
  76. package/src/components/ui/pagination/pagination.svelte +88 -0
  77. package/src/components/ui/popover/index.ts +3 -0
  78. package/src/components/ui/popover/popover-content.svelte +29 -0
  79. package/src/components/ui/popover/popover-trigger.svelte +11 -0
  80. package/src/components/ui/popover/popover.svelte +7 -0
  81. package/src/components/ui/radio-group/index.ts +3 -0
  82. package/src/components/ui/radio-group/radio-card-item.svelte +38 -0
  83. package/src/components/ui/radio-group/radio-group-item.svelte +17 -0
  84. package/src/components/ui/radio-group/radio-group.svelte +19 -0
  85. package/src/components/ui/select/index.ts +4 -0
  86. package/src/components/ui/select/select-content.svelte +38 -0
  87. package/src/components/ui/select/select-item.svelte +40 -0
  88. package/src/components/ui/select/select-scroll-down-button.svelte +23 -0
  89. package/src/components/ui/select/select-scroll-up-button.svelte +23 -0
  90. package/src/components/ui/select/select-trigger.svelte +29 -0
  91. package/src/components/ui/select/select.svelte +11 -0
  92. package/src/components/ui/sheet/index.ts +6 -0
  93. package/src/components/ui/sheet/sheet-close.svelte +7 -0
  94. package/src/components/ui/sheet/sheet-content.svelte +77 -0
  95. package/src/components/ui/sheet/sheet-description.svelte +17 -0
  96. package/src/components/ui/sheet/sheet-overlay.svelte +36 -0
  97. package/src/components/ui/sheet/sheet-title.svelte +17 -0
  98. package/src/components/ui/sheet/sheet-trigger.svelte +7 -0
  99. package/src/components/ui/sheet/sheet.svelte +7 -0
  100. package/src/components/ui/skeleton/index.ts +1 -0
  101. package/src/components/ui/skeleton/skeleton.svelte +31 -0
  102. package/src/components/ui/slider/index.ts +3 -0
  103. package/src/components/ui/slider/slider-content.svelte +59 -0
  104. package/src/components/ui/slider/slider.svelte +35 -0
  105. package/src/components/ui/sonner/index.ts +1 -0
  106. package/src/components/ui/sonner/sonner.svelte +55 -0
  107. package/src/components/ui/status-indicator/index.ts +5 -0
  108. package/src/components/ui/status-indicator/status-indicator.svelte +54 -0
  109. package/src/components/ui/table/index.ts +6 -0
  110. package/src/components/ui/table/table-body.svelte +20 -0
  111. package/src/components/ui/table/table-cell.svelte +23 -0
  112. package/src/components/ui/table/table-head.svelte +23 -0
  113. package/src/components/ui/table/table-header.svelte +20 -0
  114. package/src/components/ui/table/table-row.svelte +23 -0
  115. package/src/components/ui/table/table.svelte +22 -0
  116. package/src/components/ui/tabs/index.ts +8 -0
  117. package/src/components/ui/tabs/tabs-content.svelte +17 -0
  118. package/src/components/ui/tabs/tabs-list.svelte +40 -0
  119. package/src/components/ui/tabs/tabs-trigger.svelte +23 -0
  120. package/src/components/ui/tabs/tabs.svelte +19 -0
  121. package/src/components/ui/textarea/index.ts +1 -0
  122. package/src/components/ui/tooltip/index.ts +4 -0
  123. package/src/components/ui/tooltip/tooltip-content.svelte +50 -0
  124. package/src/components/ui/tooltip/tooltip-provider.svelte +7 -0
  125. package/src/components/ui/tooltip/tooltip-trigger.svelte +7 -0
  126. package/src/components/ui/tooltip/tooltip.svelte +7 -0
  127. package/src/core/api/admin-client.ts +45 -0
  128. package/src/core/forms/field-condition.ts +63 -0
  129. package/src/core/forms/form-controller.svelte.ts +369 -0
  130. package/src/core/forms/form-draft-recovery.ts +80 -0
  131. package/src/core/forms/form-schema.ts +609 -0
  132. package/src/core/forms/form-validation.ts +750 -0
  133. package/src/core/i18n/admin-i18n.svelte.ts +364 -0
  134. package/src/core/i18n/localized-schema.ts +111 -0
  135. package/src/core/notifications/notification-center.svelte.ts +69 -0
  136. package/src/core/notifications/validation-toast.svelte +18 -0
  137. package/src/core/plugins/field-registry.ts +60 -0
  138. package/src/core/plugins/row-label-registry.ts +62 -0
  139. package/src/core/preferences/preference-write-queue.ts +107 -0
  140. package/src/core/routing/admin-paths.ts +137 -0
  141. package/src/core/runtime/admin-runtime.svelte.ts +625 -0
  142. package/src/features/auth/account-menu.svelte +159 -0
  143. package/src/features/auth/account-navigation.svelte +44 -0
  144. package/src/features/auth/account-route.svelte +395 -0
  145. package/src/features/auth/account-security-controller.svelte.ts +119 -0
  146. package/src/features/auth/account-security-route.svelte +460 -0
  147. package/src/features/auth/auth-brand.svelte +17 -0
  148. package/src/features/auth/auth-frame.svelte +18 -0
  149. package/src/features/auth/create-first-user-controller.svelte.ts +220 -0
  150. package/src/features/auth/create-first-user-route.svelte +174 -0
  151. package/src/features/auth/forgot-password-route.svelte +78 -0
  152. package/src/features/auth/login-route.svelte +221 -0
  153. package/src/features/auth/request-verification-route.svelte +73 -0
  154. package/src/features/auth/reset-password-route.svelte +107 -0
  155. package/src/features/auth/verify-email-route.svelte +60 -0
  156. package/src/features/collections/collection-list-bulk-actions.svelte +143 -0
  157. package/src/features/collections/collection-list-bulk-editor.svelte +157 -0
  158. package/src/features/collections/collection-list-controller.svelte.ts +717 -0
  159. package/src/features/collections/collection-list-filter-popover.svelte +238 -0
  160. package/src/features/collections/collection-list-preferences-controller.svelte.ts +393 -0
  161. package/src/features/collections/collection-list-results.svelte +410 -0
  162. package/src/features/collections/collection-list-route.svelte +951 -0
  163. package/src/features/collections/collection-list-workspace-toolbar.svelte +409 -0
  164. package/src/features/collections/collection-table-skeleton.svelte +44 -0
  165. package/src/features/collections/list-workspace.ts +265 -0
  166. package/src/features/dashboard/dashboard-route.svelte +141 -0
  167. package/src/features/development/development-tools.svelte +217 -0
  168. package/src/features/documents/document-api-view-loader.svelte +31 -0
  169. package/src/features/documents/document-api-view.svelte +547 -0
  170. package/src/features/documents/document-controller.svelte.ts +1252 -0
  171. package/src/features/documents/document-field-partition.ts +18 -0
  172. package/src/features/documents/document-field-sections.svelte +46 -0
  173. package/src/features/documents/document-heading.ts +20 -0
  174. package/src/features/documents/document-route-dirty.ts +43 -0
  175. package/src/features/documents/document-route-loader.svelte +22 -0
  176. package/src/features/documents/document-route.svelte +1124 -0
  177. package/src/features/documents/live-preview-panel.svelte +390 -0
  178. package/src/features/documents/live-preview.ts +61 -0
  179. package/src/features/documents/upload-document-preview-loader.svelte +40 -0
  180. package/src/features/documents/upload-document-preview.svelte +525 -0
  181. package/src/features/localization/content-locale-switcher.svelte +93 -0
  182. package/src/features/navigation/admin-breadcrumbs.svelte +124 -0
  183. package/src/features/navigation/admin-command-menu.svelte +245 -0
  184. package/src/features/navigation/admin-resource-groups.ts +72 -0
  185. package/src/features/reference-browser/reference-browser-loader.svelte +15 -0
  186. package/src/features/reference-browser/reference-browser-workflow.svelte.ts +691 -0
  187. package/src/features/reference-browser/reference-browser.svelte +844 -0
  188. package/src/features/uploads/bulk-upload-route.svelte +624 -0
  189. package/src/features/uploads/bulk-upload.ts +39 -0
  190. package/src/features/uploads/upload-metadata-fields.svelte +112 -0
  191. package/src/features/versions/version-diff.ts +72 -0
  192. package/src/features/versions/version-history-route.svelte +581 -0
  193. package/src/fields/field-clipboard.ts +132 -0
  194. package/src/fields/field-layout.svelte +60 -0
  195. package/src/fields/field-layout.ts +57 -0
  196. package/src/fields/field-messages.svelte +29 -0
  197. package/src/fields/field-renderer.svelte +152 -0
  198. package/src/fields/field-shell.svelte +30 -0
  199. package/src/fields/field-tab-layout.svelte +99 -0
  200. package/src/fields/join/join-field.svelte +358 -0
  201. package/src/fields/localized-field-presentation.ts +17 -0
  202. package/src/fields/nested/nested-field.svelte +602 -0
  203. package/src/fields/nested/scoped-field.ts +78 -0
  204. package/src/fields/nested/sortable-row.svelte +32 -0
  205. package/src/fields/point/point-field.svelte +52 -0
  206. package/src/fields/radio/radio-field.svelte +34 -0
  207. package/src/fields/relationship/relationship-field-controller.svelte.ts +245 -0
  208. package/src/fields/relationship/relationship-field.svelte +258 -0
  209. package/src/fields/relationship/relationship-lookup-controller.svelte.ts +129 -0
  210. package/src/fields/relationship/relationship-query.ts +88 -0
  211. package/src/fields/relationship/relationship-quick-picker-controller.svelte.ts +198 -0
  212. package/src/fields/relationship/relationship-quick-picker.svelte +327 -0
  213. package/src/fields/relationship/relationship-value.ts +47 -0
  214. package/src/fields/scalar/date-control-value.ts +60 -0
  215. package/src/fields/scalar/date-value.ts +26 -0
  216. package/src/fields/scalar/scalar-field.svelte +137 -0
  217. package/src/fields/select/select-field.svelte +132 -0
  218. package/src/fields/select/select-value.ts +14 -0
  219. package/src/fields/text/slug-field.svelte +87 -0
  220. package/src/fields/text/slug.ts +38 -0
  221. package/src/fields/text/text-field.svelte +41 -0
  222. package/src/fields/ui/ui-field.svelte +12 -0
  223. package/src/fields/virtual/virtual-field.svelte +28 -0
  224. package/src/index.ts +49 -0
  225. package/src/main.ts +12 -0
  226. package/src/vite-env.d.ts +9 -0
@@ -0,0 +1,30 @@
1
+ <script lang="ts">
2
+ import { Calendar as CalendarPrimitive } from "bits-ui";
3
+ import ChevronLeftIcon from "~icons/lucide/chevron-left";
4
+
5
+ import { buttonVariants, type ButtonVariant } from "@admin/components/ui/button";
6
+ import { cn } from "@riducms/ui";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ class: className,
11
+ children,
12
+ variant = "ghost",
13
+ ...restProps
14
+ }: CalendarPrimitive.PrevButtonProps & { variant?: ButtonVariant } = $props();
15
+ </script>
16
+
17
+ {#snippet fallback()}
18
+ <ChevronLeftIcon class="size-3.5" aria-hidden="true" />
19
+ {/snippet}
20
+
21
+ <CalendarPrimitive.PrevButton
22
+ bind:ref
23
+ class={cn(
24
+ buttonVariants({ variant, size: "icon-sm" }),
25
+ "size-(--calendar-cell-size) bg-transparent p-0 disabled:opacity-35 rtl:rotate-180",
26
+ className
27
+ )}
28
+ children={children ?? fallback}
29
+ {...restProps}
30
+ />
@@ -0,0 +1,44 @@
1
+ <script lang="ts">
2
+ import { Calendar as CalendarPrimitive } from "bits-ui";
3
+ import ChevronDownIcon from "~icons/lucide/chevron-down";
4
+
5
+ import { cn, type WithoutChildrenOrChild } from "@riducms/ui";
6
+
7
+ let {
8
+ ref = $bindable(null),
9
+ class: className,
10
+ value,
11
+ ...restProps
12
+ }: WithoutChildrenOrChild<CalendarPrimitive.YearSelectProps> = $props();
13
+ </script>
14
+
15
+ <span
16
+ class={cn(
17
+ "relative flex rounded-md border border-control-border bg-control transition-colors focus-within:border-primary/60 focus-within:ring-2 focus-within:ring-primary/15",
18
+ className
19
+ )}
20
+ >
21
+ <CalendarPrimitive.YearSelect bind:ref class="absolute inset-0 opacity-0" {...restProps}>
22
+ {#snippet child({ props, yearItems, selectedYearItem })}
23
+ <select {...props} {value} data-ridu-native-exception>
24
+ {#each yearItems as yearItem (yearItem.value)}
25
+ <option
26
+ value={yearItem.value}
27
+ selected={value === undefined
28
+ ? yearItem.value === selectedYearItem.value
29
+ : yearItem.value === value}
30
+ >
31
+ {yearItem.label}
32
+ </option>
33
+ {/each}
34
+ </select>
35
+ <span
36
+ class="flex h-8 items-center gap-1 ps-2 pe-1 text-[12px] font-medium text-foreground select-none"
37
+ aria-hidden="true"
38
+ >
39
+ {yearItems.find((item) => item.value === value)?.label ?? selectedYearItem.label}
40
+ <ChevronDownIcon class="size-3 text-foreground-faint" />
41
+ </span>
42
+ {/snippet}
43
+ </CalendarPrimitive.YearSelect>
44
+ </span>
@@ -0,0 +1,118 @@
1
+ <script lang="ts">
2
+ import { isEqualMonth, type DateValue } from "@internationalized/date";
3
+ import { Calendar as CalendarPrimitive } from "bits-ui";
4
+ import type { Snippet } from "svelte";
5
+
6
+ import CalendarCaption from "@admin/components/ui/calendar/calendar-caption.svelte";
7
+ import CalendarCell from "@admin/components/ui/calendar/calendar-cell.svelte";
8
+ import CalendarDay from "@admin/components/ui/calendar/calendar-day.svelte";
9
+ import CalendarGridRow from "@admin/components/ui/calendar/calendar-grid-row.svelte";
10
+ import CalendarGrid from "@admin/components/ui/calendar/calendar-grid.svelte";
11
+ import CalendarHeadCell from "@admin/components/ui/calendar/calendar-head-cell.svelte";
12
+ import CalendarHeader from "@admin/components/ui/calendar/calendar-header.svelte";
13
+ import CalendarMonth from "@admin/components/ui/calendar/calendar-month.svelte";
14
+ import CalendarMonths from "@admin/components/ui/calendar/calendar-months.svelte";
15
+ import CalendarNav from "@admin/components/ui/calendar/calendar-nav.svelte";
16
+ import CalendarNextButton from "@admin/components/ui/calendar/calendar-next-button.svelte";
17
+ import CalendarPrevButton from "@admin/components/ui/calendar/calendar-prev-button.svelte";
18
+ import { cn, type ButtonVariant, type WithoutChildrenOrChild } from "@riducms/ui";
19
+
20
+ let {
21
+ ref = $bindable(null),
22
+ value = $bindable(),
23
+ placeholder = $bindable(),
24
+ class: className,
25
+ weekdayFormat = "short",
26
+ buttonVariant = "ghost",
27
+ captionLayout = "label",
28
+ locale = "en-US",
29
+ months: availableMonths,
30
+ years,
31
+ monthFormat: requestedMonthFormat,
32
+ yearFormat = "numeric",
33
+ day,
34
+ disableDaysOutsideMonth = false,
35
+ ...restProps
36
+ }: WithoutChildrenOrChild<CalendarPrimitive.RootProps> & {
37
+ buttonVariant?: ButtonVariant;
38
+ captionLayout?: "dropdown" | "dropdown-months" | "dropdown-years" | "label";
39
+ months?: CalendarPrimitive.MonthSelectProps["months"];
40
+ years?: CalendarPrimitive.YearSelectProps["years"];
41
+ monthFormat?: CalendarPrimitive.MonthSelectProps["monthFormat"];
42
+ yearFormat?: CalendarPrimitive.YearSelectProps["yearFormat"];
43
+ day?: Snippet<[{ day: DateValue; outsideMonth: boolean }]>;
44
+ } = $props();
45
+
46
+ const monthFormat = $derived(
47
+ requestedMonthFormat ?? (captionLayout.startsWith("dropdown") ? "short" : "long")
48
+ );
49
+ </script>
50
+
51
+ <CalendarPrimitive.Root
52
+ bind:value={value as never}
53
+ bind:ref
54
+ bind:placeholder
55
+ {weekdayFormat}
56
+ {disableDaysOutsideMonth}
57
+ class={cn(
58
+ "group/calendar bg-popover p-3 text-popover-foreground [--calendar-cell-size:2rem]",
59
+ className
60
+ )}
61
+ {locale}
62
+ {monthFormat}
63
+ {yearFormat}
64
+ {...restProps}
65
+ >
66
+ {#snippet children({ months, weekdays })}
67
+ <CalendarMonths>
68
+ <CalendarNav>
69
+ <CalendarPrevButton variant={buttonVariant} />
70
+ <CalendarNextButton variant={buttonVariant} />
71
+ </CalendarNav>
72
+ {#each months as month, monthIndex (month.value)}
73
+ <CalendarMonth>
74
+ <CalendarHeader>
75
+ <CalendarCaption
76
+ {captionLayout}
77
+ months={availableMonths}
78
+ {monthFormat}
79
+ {years}
80
+ {yearFormat}
81
+ month={month.value}
82
+ bind:placeholder
83
+ {locale}
84
+ {monthIndex}
85
+ />
86
+ </CalendarHeader>
87
+ <CalendarGrid>
88
+ <CalendarPrimitive.GridHead>
89
+ <CalendarGridRow>
90
+ {#each weekdays as weekday (weekday)}
91
+ <CalendarHeadCell>{weekday.slice(0, 2)}</CalendarHeadCell>
92
+ {/each}
93
+ </CalendarGridRow>
94
+ </CalendarPrimitive.GridHead>
95
+ <CalendarPrimitive.GridBody>
96
+ {#each month.weeks as weekDates (weekDates)}
97
+ <CalendarGridRow>
98
+ {#each weekDates as date (date)}
99
+ <CalendarCell {date} month={month.value}>
100
+ {#if day}
101
+ {@render day({
102
+ day: date,
103
+ outsideMonth: !isEqualMonth(date, month.value),
104
+ })}
105
+ {:else}
106
+ <CalendarDay />
107
+ {/if}
108
+ </CalendarCell>
109
+ {/each}
110
+ </CalendarGridRow>
111
+ {/each}
112
+ </CalendarPrimitive.GridBody>
113
+ </CalendarGrid>
114
+ </CalendarMonth>
115
+ {/each}
116
+ </CalendarMonths>
117
+ {/snippet}
118
+ </CalendarPrimitive.Root>
@@ -0,0 +1 @@
1
+ export { default as Calendar } from "@admin/components/ui/calendar/calendar.svelte";
@@ -0,0 +1,35 @@
1
+ <script lang="ts">
2
+ import { Checkbox as CheckboxPrimitive } from "bits-ui";
3
+ import CheckIcon from "~icons/lucide/check";
4
+ import MinusIcon from "~icons/lucide/minus";
5
+
6
+ import { cn, type WithoutChildrenOrChild } from "@riducms/ui";
7
+
8
+ let {
9
+ ref = $bindable(null),
10
+ checked = $bindable(false),
11
+ indeterminate = $bindable(false),
12
+ class: className,
13
+ ...restProps
14
+ }: WithoutChildrenOrChild<CheckboxPrimitive.RootProps> = $props();
15
+ </script>
16
+
17
+ <CheckboxPrimitive.Root
18
+ bind:ref
19
+ bind:checked
20
+ bind:indeterminate
21
+ data-slot="checkbox"
22
+ class={cn(
23
+ "grid size-4 shrink-0 place-items-center rounded-[4px] border border-control-border bg-control text-primary-foreground transition-[background-color,border-color,opacity] duration-150 outline-none focus-visible:outline-2 focus-visible:outline-primary/60 focus-visible:outline-offset-2 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary data-[disabled]:cursor-not-allowed data-[disabled]:border-control-border-disabled data-[disabled]:bg-control-disabled data-[disabled]:opacity-50",
24
+ className
25
+ )}
26
+ {...restProps}
27
+ >
28
+ {#snippet children({ checked, indeterminate })}
29
+ {#if indeterminate}
30
+ <MinusIcon class="size-3 stroke-[2.5]" aria-hidden="true" />
31
+ {:else if checked}
32
+ <CheckIcon class="size-3 stroke-[2.5]" aria-hidden="true" />
33
+ {/if}
34
+ {/snippet}
35
+ </CheckboxPrimitive.Root>
@@ -0,0 +1 @@
1
+ export { default as Checkbox } from "@admin/components/ui/checkbox/checkbox.svelte";
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import { getAdminI18n } from "@riducms/plugin";
3
+ import { ConfirmationDialog } from "@riducms/ui";
4
+
5
+ let {
6
+ open = $bindable(false),
7
+ title,
8
+ description,
9
+ confirmLabel,
10
+ cancelLabel,
11
+ destructive = false,
12
+ disabled = false,
13
+ onconfirm,
14
+ }: {
15
+ open?: boolean;
16
+ title: string;
17
+ description: string;
18
+ confirmLabel: string;
19
+ cancelLabel?: string;
20
+ destructive?: boolean;
21
+ disabled?: boolean;
22
+ onconfirm: () => void | Promise<void>;
23
+ } = $props();
24
+ const i18n = getAdminI18n();
25
+ const resolvedCancelLabel = $derived(cancelLabel ?? i18n.t("general:cancel"));
26
+ </script>
27
+
28
+ <ConfirmationDialog
29
+ bind:open
30
+ {title}
31
+ {description}
32
+ {confirmLabel}
33
+ cancelLabel={resolvedCancelLabel}
34
+ {destructive}
35
+ {disabled}
36
+ {onconfirm}
37
+ />
@@ -0,0 +1 @@
1
+ export { default as ConfirmationDialog } from "@admin/components/ui/confirmation-dialog/confirmation-dialog.svelte";
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import type { DateValue } from "@internationalized/date";
3
+
4
+ import { Calendar } from "@admin/components/ui/calendar";
5
+
6
+ let {
7
+ value,
8
+ disabled = false,
9
+ readonly = false,
10
+ required = false,
11
+ locale,
12
+ calendarLabel,
13
+ onValueChange,
14
+ }: {
15
+ value?: DateValue;
16
+ disabled?: boolean;
17
+ readonly?: boolean;
18
+ required?: boolean;
19
+ locale: string;
20
+ calendarLabel: string;
21
+ onValueChange: (value: DateValue | undefined) => void;
22
+ } = $props();
23
+ </script>
24
+
25
+ <Calendar
26
+ type="single"
27
+ {value}
28
+ {disabled}
29
+ {readonly}
30
+ preventDeselect={required}
31
+ initialFocus
32
+ fixedWeeks
33
+ captionLayout="dropdown"
34
+ {locale}
35
+ {calendarLabel}
36
+ onValueChange={(next) => onValueChange(next as DateValue | undefined)}
37
+ />
@@ -0,0 +1,36 @@
1
+ <script lang="ts">
2
+ import type { SchemaDatePickerAppearance } from "@riducms/protocol";
3
+ import type { Component } from "svelte";
4
+
5
+ type ControlSize = "field" | "compact" | "toolbar";
6
+ type DateValueControlProps = {
7
+ id: string;
8
+ name?: string;
9
+ appearance?: SchemaDatePickerAppearance;
10
+ value?: string;
11
+ disabled?: boolean;
12
+ readonly?: boolean;
13
+ required?: boolean;
14
+ invalid?: boolean;
15
+ label?: string;
16
+ describedBy?: string;
17
+ class?: string;
18
+ size?: ControlSize;
19
+ onValueChange: (value: string) => void;
20
+ };
21
+
22
+ let props: DateValueControlProps = $props();
23
+ let Control = $state<Component<DateValueControlProps> | undefined>(undefined);
24
+
25
+ void import("@admin/components/ui/date-value-control/date-value-control.svelte").then(
26
+ ({ default: component }) => (Control = component)
27
+ );
28
+ </script>
29
+
30
+ {#if Control !== undefined}
31
+ <Control {...props} />
32
+ {:else}
33
+ <div id={props.id} class={props.class} role="status" aria-label={props.label} aria-busy="true">
34
+ Loading date control…
35
+ </div>
36
+ {/if}
@@ -0,0 +1,177 @@
1
+ <script lang="ts">
2
+ import type { DateValue, Time } from "@internationalized/date";
3
+ import type { SchemaDatePickerAppearance } from "@riducms/protocol";
4
+ import { DateField, TimeField } from "bits-ui";
5
+ import CalendarIcon from "~icons/lucide/calendar";
6
+
7
+ import { buttonVariants } from "@admin/components/ui/button";
8
+ import DateValueCalendar from "@admin/components/ui/date-value-control/date-value-calendar.svelte";
9
+ import { Popover, PopoverContent, PopoverTrigger } from "@admin/components/ui/popover";
10
+ import { cn } from "@riducms/ui";
11
+ import { getAdminI18n } from "@riducms/plugin";
12
+ import {
13
+ datePickerFormValue,
14
+ datePickerValue,
15
+ timeFieldFormValue,
16
+ timeFieldValue,
17
+ } from "@admin/fields/scalar/date-control-value";
18
+
19
+ type ControlSize = "field" | "compact" | "toolbar";
20
+ let {
21
+ id,
22
+ name,
23
+ appearance = "dayOnly",
24
+ value = "",
25
+ disabled = false,
26
+ readonly = false,
27
+ required = false,
28
+ invalid = false,
29
+ label,
30
+ describedBy,
31
+ class: className,
32
+ size = "field",
33
+ onValueChange,
34
+ }: {
35
+ id: string;
36
+ name?: string;
37
+ appearance?: SchemaDatePickerAppearance;
38
+ value?: string;
39
+ disabled?: boolean;
40
+ readonly?: boolean;
41
+ required?: boolean;
42
+ invalid?: boolean;
43
+ label?: string;
44
+ describedBy?: string;
45
+ class?: string;
46
+ size?: ControlSize;
47
+ onValueChange: (value: string) => void;
48
+ } = $props();
49
+ const i18n = getAdminI18n();
50
+
51
+ const controlClass = $derived(
52
+ cn(
53
+ "flex w-full items-center rounded-lg border border-control-border bg-control text-foreground-strong transition-[background-color,border-color,color] duration-150 hover:border-control-border-hover focus-within:border-primary/65 aria-invalid:border-destructive/65 data-[disabled]:cursor-not-allowed data-[disabled]:border-control-border-disabled data-[disabled]:bg-control-disabled data-[disabled]:opacity-45 data-[readonly]:border-control-border-disabled data-[readonly]:bg-control-disabled",
54
+ size === "field" && "h-10.5 px-3.25 text-[14.5px]",
55
+ size === "compact" && "h-9 px-3 text-[13px]",
56
+ size === "toolbar" && "h-[34px] px-2.5 text-[12.5px]",
57
+ className
58
+ )
59
+ );
60
+ const selectedDate = $derived(datePickerValue(value, appearance, i18n.timeZone));
61
+ let open = $state(false);
62
+
63
+ function updateDate(next: DateValue | undefined) {
64
+ onValueChange(datePickerFormValue(next, appearance, i18n.timeZone));
65
+ }
66
+
67
+ function selectCalendarDate(next: DateValue | undefined) {
68
+ updateDate(next);
69
+ open = false;
70
+ }
71
+
72
+ function updateTime(next: Time | undefined) {
73
+ onValueChange(timeFieldFormValue(next));
74
+ }
75
+ </script>
76
+
77
+ {#if appearance === "timeOnly"}
78
+ <TimeField.Root
79
+ value={timeFieldValue(value)}
80
+ locale={i18n.language}
81
+ {disabled}
82
+ {readonly}
83
+ {required}
84
+ errorMessageId={invalid ? describedBy : undefined}
85
+ onValueChange={updateTime}
86
+ >
87
+ <TimeField.Input
88
+ {id}
89
+ {name}
90
+ class={cn(controlClass, "gap-0.5 select-none")}
91
+ data-disabled={disabled ? "" : undefined}
92
+ data-readonly={readonly ? "" : undefined}
93
+ aria-invalid={invalid}
94
+ aria-label={label}
95
+ aria-describedby={describedBy}
96
+ aria-errormessage={invalid ? describedBy : undefined}
97
+ >
98
+ {#snippet children({ segments })}
99
+ {#each segments as { part, value: segmentValue }, index (`${part}:${index}`)}
100
+ <TimeField.Segment
101
+ {part}
102
+ class={part === "literal"
103
+ ? "px-0.5 text-foreground-soft"
104
+ : "rounded px-0.5 outline-none hover:bg-control-hover focus:bg-primary/15 aria-[valuetext=Empty]:text-foreground-placeholder"}
105
+ >
106
+ {segmentValue}
107
+ </TimeField.Segment>
108
+ {/each}
109
+ {/snippet}
110
+ </TimeField.Input>
111
+ </TimeField.Root>
112
+ {:else}
113
+ <DateField.Root
114
+ value={selectedDate}
115
+ locale={i18n.language}
116
+ granularity={appearance === "dayAndTime" ? "minute" : "day"}
117
+ {disabled}
118
+ {readonly}
119
+ {required}
120
+ errorMessageId={invalid ? describedBy : undefined}
121
+ onValueChange={updateDate}
122
+ >
123
+ <div
124
+ class={controlClass}
125
+ data-disabled={disabled ? "" : undefined}
126
+ data-readonly={readonly ? "" : undefined}
127
+ aria-invalid={invalid}
128
+ >
129
+ <DateField.Input
130
+ {id}
131
+ {name}
132
+ class="flex min-w-0 flex-1 items-center gap-0.5 select-none"
133
+ aria-label={label}
134
+ aria-describedby={describedBy}
135
+ aria-errormessage={invalid ? describedBy : undefined}
136
+ >
137
+ {#snippet children({ segments })}
138
+ {#each segments as { part, value: segmentValue }, index (`${part}:${index}`)}
139
+ <DateField.Segment
140
+ {part}
141
+ class={part === "literal"
142
+ ? "px-0.5 text-foreground-soft"
143
+ : "rounded px-0.5 outline-none hover:bg-control-hover focus:bg-primary/15 aria-[valuetext=Empty]:text-foreground-placeholder"}
144
+ >
145
+ {segmentValue}
146
+ </DateField.Segment>
147
+ {/each}
148
+ <Popover bind:open>
149
+ <PopoverTrigger
150
+ type="button"
151
+ class={buttonVariants({
152
+ variant: "ghost",
153
+ size: "icon-sm",
154
+ class: "ms-auto size-7 text-foreground-soft",
155
+ })}
156
+ disabled={disabled || readonly}
157
+ aria-label={i18n.t("fields:openCalendar")}
158
+ >
159
+ <CalendarIcon class="size-3.5" aria-hidden="true" />
160
+ </PopoverTrigger>
161
+ <PopoverContent align="end" sideOffset={6} class="w-auto gap-0 overflow-hidden p-0">
162
+ <DateValueCalendar
163
+ value={selectedDate}
164
+ {disabled}
165
+ {readonly}
166
+ {required}
167
+ locale={i18n.language}
168
+ calendarLabel={i18n.t("fields:selectDate")}
169
+ onValueChange={selectCalendarDate}
170
+ />
171
+ </PopoverContent>
172
+ </Popover>
173
+ {/snippet}
174
+ </DateField.Input>
175
+ </div>
176
+ </DateField.Root>
177
+ {/if}
@@ -0,0 +1,3 @@
1
+ import DateValueControl from "@admin/components/ui/date-value-control/date-value-control-loader.svelte";
2
+
3
+ export { DateValueControl };
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+
4
+ let {
5
+ ref = $bindable(null),
6
+ type = "button",
7
+ ...restProps
8
+ }: DialogPrimitive.CloseProps = $props();
9
+ </script>
10
+
11
+ <DialogPrimitive.Close bind:ref data-slot="dialog-close" {type} {...restProps} />
@@ -0,0 +1,52 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+ import XIcon from "~icons/lucide/x";
4
+ import { getAdminI18n } from "@riducms/plugin";
5
+ import { buttonVariants } from "@admin/components/ui/button/index.js";
6
+ import { cn, type WithoutChildrenOrChild } from "@riducms/ui";
7
+ import DialogOverlay from "@admin/components/ui/dialog/dialog-overlay.svelte";
8
+ import type { Snippet } from "svelte";
9
+
10
+ let {
11
+ ref = $bindable(null),
12
+ class: className,
13
+ portalProps,
14
+ children,
15
+ showCloseButton = true,
16
+ ...restProps
17
+ }: WithoutChildrenOrChild<DialogPrimitive.ContentProps> & {
18
+ portalProps?: WithoutChildrenOrChild<DialogPrimitive.PortalProps>;
19
+ children: Snippet;
20
+ showCloseButton?: boolean;
21
+ } = $props();
22
+ const i18n = getAdminI18n();
23
+ </script>
24
+
25
+ <DialogPrimitive.Portal {...portalProps}>
26
+ <DialogOverlay />
27
+ <DialogPrimitive.Content
28
+ bind:ref
29
+ data-slot="dialog-content"
30
+ class={cn(
31
+ "ridu-dialog-enter grid max-w-[calc(100%-2rem)] gap-6 rounded-[4px] border border-control-border bg-popover p-6.5 text-[14.5px] text-popover-foreground shadow-[var(--shadow-dialog)] sm:max-w-[460px] fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 outline-none",
32
+ className
33
+ )}
34
+ {...restProps}
35
+ >
36
+ {@render children?.()}
37
+ {#if showCloseButton}
38
+ <DialogPrimitive.Close
39
+ type="button"
40
+ data-slot="dialog-close"
41
+ class={buttonVariants({
42
+ variant: "ghost",
43
+ size: "icon-sm",
44
+ class: "absolute top-4 end-4",
45
+ })}
46
+ >
47
+ <XIcon />
48
+ <span class="sr-only">{i18n.t("general:close")}</span>
49
+ </DialogPrimitive.Close>
50
+ {/if}
51
+ </DialogPrimitive.Content>
52
+ </DialogPrimitive.Portal>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+ import { cn } from "@riducms/ui";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: DialogPrimitive.DescriptionProps = $props();
10
+ </script>
11
+
12
+ <DialogPrimitive.Description
13
+ bind:ref
14
+ data-slot="dialog-description"
15
+ class={cn(
16
+ "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground",
17
+ className
18
+ )}
19
+ {...restProps}
20
+ />
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "@riducms/ui";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="dialog-footer"
16
+ class={cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { cn, type WithElementRef } from "@riducms/ui";
3
+ import type { HTMLAttributes } from "svelte/elements";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ children,
9
+ ...restProps
10
+ }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
11
+ </script>
12
+
13
+ <div
14
+ bind:this={ref}
15
+ data-slot="dialog-header"
16
+ class={cn("gap-1.5 flex flex-col", className)}
17
+ {...restProps}
18
+ >
19
+ {@render children?.()}
20
+ </div>
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { Dialog as DialogPrimitive } from "bits-ui";
3
+ import { cn } from "@riducms/ui";
4
+
5
+ let {
6
+ ref = $bindable(null),
7
+ class: className,
8
+ ...restProps
9
+ }: DialogPrimitive.OverlayProps = $props();
10
+ </script>
11
+
12
+ <DialogPrimitive.Overlay
13
+ bind:ref
14
+ data-slot="dialog-overlay"
15
+ class={cn(
16
+ "bg-[rgba(8,7,6,0.55)] supports-backdrop-filter:backdrop-blur-[4px] data-[state=open]:animate-fade-in data-[state=open]:duration-150 fixed inset-0 isolate z-50",
17
+ className
18
+ )}
19
+ {...restProps}
20
+ />