@reblu/site-blocks 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { ReactNode } from 'react';
4
- import { ShopProductListItem, DataRequestType, DataRequestInput, DataRequestSubmission } from '@reblu/site-contracts';
4
+ import { ShopProductListItem, AcademyModulePublic, AcademyLessonPublic, DataRequestType, DataRequestInput, DataRequestSubmission } from '@reblu/site-contracts';
5
5
  export { DATA_REQUEST_TYPES } from '@reblu/site-contracts';
6
6
  import { H as HeadingLevel } from './_heading-BsNbc1wc.js';
7
7
 
@@ -305,6 +305,55 @@ declare function ProductCarousel<T extends {
305
305
  id: string | number;
306
306
  } = ShopProductListItem>(props: ProductCarouselProps<T>): react_jsx_runtime.JSX.Element | null;
307
307
 
308
+ /**
309
+ * `CourseSyllabus` — the drop-in programme of a public course page, over
310
+ * `AcademyCourseDetail.modules` (`client.academy.bySlug()`), REB-1134.
311
+ *
312
+ * - The header reads the heading, then «N módulos · M lecciones».
313
+ * - Each module with lessons is a `<button>` with `aria-expanded` and
314
+ * `aria-controls`, showing its lesson count and, when every lesson has one,
315
+ * the module's total duration. Expanding it lists the lessons in the order
316
+ * the API returns them, with their duration and the free-preview flag.
317
+ * - A module without lessons is a plain row (title only), never a button.
318
+ *
319
+ * It renders only what the API serves. The API returns published lessons only
320
+ * and no video, playback or attachment data, so nothing here can leak it.
321
+ *
322
+ * Client Component: it holds the open/closed state of each module. Every prop
323
+ * is serialisable (copy is plain strings), so a Server Component page can
324
+ * render it directly.
325
+ */
326
+ interface CourseSyllabusLabels {
327
+ heading: string;
328
+ moduleSingular: string;
329
+ modulePlural: string;
330
+ lessonSingular: string;
331
+ lessonPlural: string;
332
+ /** Badge on a lesson with `isFreePreview`. */
333
+ freePreview: string;
334
+ /** Hours unit in durations («1 h 15 min»). */
335
+ hours: string;
336
+ /** Minutes unit in durations. */
337
+ minutes: string;
338
+ }
339
+ declare const DEFAULT_COURSE_SYLLABUS_LABELS: CourseSyllabusLabels;
340
+ /** A module as served. `lessons` is optional so an older payload still renders. */
341
+ type CourseSyllabusModule = Pick<AcademyModulePublic, 'id' | 'title'> & {
342
+ description?: string | null;
343
+ lessons?: readonly AcademyLessonPublic[];
344
+ };
345
+ interface CourseSyllabusProps {
346
+ /** `AcademyCourseDetail.modules`, in the order the API returns them. */
347
+ modules: readonly CourseSyllabusModule[];
348
+ labels?: Partial<CourseSyllabusLabels>;
349
+ /** Level of the heading. Default `2`. */
350
+ headingLevel?: HeadingLevel;
351
+ /** Replaces the heading's default typography (see the className rule in the README). */
352
+ headingClassName?: string;
353
+ className?: string;
354
+ }
355
+ declare function CourseSyllabus({ modules, labels: labelOverrides, headingLevel, headingClassName, className, }: CourseSyllabusProps): react_jsx_runtime.JSX.Element | null;
356
+
308
357
  /**
309
358
  * `DataRequestForm` — drop-in public GDPR rights form (REB-980) over
310
359
  * `POST /api/site/data-requests` (REB-77). The visitor picks the right they
@@ -384,4 +433,4 @@ interface DataRequestFormProps {
384
433
  }
385
434
  declare function DataRequestForm({ getCaptchaToken, submit, endpoint, onInteract, onSubmitted, requestTypes, labels, locale, className, }: DataRequestFormProps): react_jsx_runtime.JSX.Element;
386
435
 
387
- export { AddToCartButton, type AddToCartButtonLabels, type AddToCartButtonProps, type AddToCartButtonStatus, CartIcon, type CartIconLabels, type CartIconProps, Collection, type CollectionFacet, type CollectionFacetOption, type CollectionFilter, type CollectionLabels, type CollectionProps, DATA_REQUEST_FIELD_LIMITS, DEFAULT_DATA_REQUEST_FORM_LABELS, DEFAULT_PRODUCT_CAROUSEL_LABELS, DataRequestForm, type DataRequestFormLabels, type DataRequestFormProps, type DataRequestSubmitResult, ProductCarousel, type ProductCarouselCustomCardProps, type ProductCarouselDefaultCardProps, type ProductCarouselLabels, type ProductCarouselProps, ShareButtons, type ShareButtonsLabels, type ShareButtonsProps, type UseCollectionOptions, type UseCollectionResult, useCollection };
436
+ export { AddToCartButton, type AddToCartButtonLabels, type AddToCartButtonProps, type AddToCartButtonStatus, CartIcon, type CartIconLabels, type CartIconProps, Collection, type CollectionFacet, type CollectionFacetOption, type CollectionFilter, type CollectionLabels, type CollectionProps, CourseSyllabus, type CourseSyllabusLabels, type CourseSyllabusModule, type CourseSyllabusProps, DATA_REQUEST_FIELD_LIMITS, DEFAULT_COURSE_SYLLABUS_LABELS, DEFAULT_DATA_REQUEST_FORM_LABELS, DEFAULT_PRODUCT_CAROUSEL_LABELS, DataRequestForm, type DataRequestFormLabels, type DataRequestFormProps, type DataRequestSubmitResult, ProductCarousel, type ProductCarouselCustomCardProps, type ProductCarouselDefaultCardProps, type ProductCarouselLabels, type ProductCarouselProps, ShareButtons, type ShareButtonsLabels, type ShareButtonsProps, type UseCollectionOptions, type UseCollectionResult, useCollection };
package/dist/client.js CHANGED
@@ -415,7 +415,7 @@ import { cn as cn4 } from "@reblu/site-ui/utils";
415
415
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
416
416
  var DEFAULT_LABELS4 = {
417
417
  cart: "Carrito",
418
- itemsSuffix: (count) => `${count} art\xEDculo${count === 1 ? "" : "s"}`
418
+ itemsSuffix: (count2) => `${count2} art\xEDculo${count2 === 1 ? "" : "s"}`
419
419
  };
420
420
  var BUMP_DURATION_MS = 400;
421
421
  function CartIcon({ itemCount, href, hydrated, bumpOnAdd, labels, className }) {
@@ -687,13 +687,201 @@ function ProductCarousel(props) {
687
687
  ] });
688
688
  }
689
689
 
690
- // src/components/data-request-form.tsx
691
- import { useEffect as useEffect4, useId as useId2, useRef as useRef4, useState as useState6 } from "react";
690
+ // src/components/course-syllabus.tsx
691
+ import { useId as useId2, useState as useState6 } from "react";
692
+ import { cn as cn8 } from "@reblu/site-ui/utils";
693
+
694
+ // src/lib/slot-class-name.ts
692
695
  import { cn as cn7 } from "@reblu/site-ui/utils";
696
+ var MERGE_SAFE_TEXT = /(?:^|:)!?text-(?:left|center|right|justify|start|end|wrap|nowrap|balance|pretty|ellipsis|clip)$/;
697
+ var TEXT_UTILITY = /(?:^|:)!?-?text-/;
698
+ function bypassesMerge(token) {
699
+ return TEXT_UTILITY.test(token) && !MERGE_SAFE_TEXT.test(token);
700
+ }
701
+ function slotClassName(structural, defaults, consumer) {
702
+ if (consumer === void 0 || consumer.trim() === "") return cn7(structural, defaults);
703
+ const tokens = consumer.split(/\s+/).filter(Boolean);
704
+ const verbatim = tokens.filter(bypassesMerge);
705
+ const merged = cn7(structural, tokens.filter((token) => !bypassesMerge(token)));
706
+ return [merged, ...verbatim].filter(Boolean).join(" ");
707
+ }
708
+
709
+ // src/components/course-syllabus.tsx
710
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
711
+ var DEFAULT_COURSE_SYLLABUS_LABELS = {
712
+ heading: "Programa",
713
+ moduleSingular: "m\xF3dulo",
714
+ modulePlural: "m\xF3dulos",
715
+ lessonSingular: "lecci\xF3n",
716
+ lessonPlural: "lecciones",
717
+ freePreview: "Vista previa gratuita",
718
+ hours: "h",
719
+ minutes: "min"
720
+ };
721
+ var SEPARATOR = " \xB7 ";
722
+ function count(n, singular, plural) {
723
+ return `${n} ${n === 1 ? singular : plural}`;
724
+ }
725
+ function formatDuration(seconds, labels) {
726
+ const totalMinutes = Math.max(1, Math.round(seconds / 60));
727
+ const hours = Math.floor(totalMinutes / 60);
728
+ const minutes = totalMinutes % 60;
729
+ if (hours === 0) return `${minutes} ${labels.minutes}`;
730
+ return minutes === 0 ? `${hours} ${labels.hours}` : `${hours} ${labels.hours} ${minutes} ${labels.minutes}`;
731
+ }
732
+ function moduleSeconds(lessons) {
733
+ let total = 0;
734
+ for (const l of lessons) {
735
+ if (typeof l.durationSeconds !== "number" || l.durationSeconds <= 0) return null;
736
+ total += l.durationSeconds;
737
+ }
738
+ return total;
739
+ }
740
+ function CourseSyllabus({
741
+ modules,
742
+ labels: labelOverrides,
743
+ headingLevel = 2,
744
+ headingClassName,
745
+ className
746
+ }) {
747
+ const labels = { ...DEFAULT_COURSE_SYLLABUS_LABELS, ...labelOverrides };
748
+ const baseId = useId2();
749
+ const [open, setOpen] = useState6(() => /* @__PURE__ */ new Set());
750
+ if (modules.length === 0) return null;
751
+ const totalLessons = modules.reduce((sum, m) => sum + (m.lessons?.length ?? 0), 0);
752
+ const summary = [count(modules.length, labels.moduleSingular, labels.modulePlural)];
753
+ if (totalLessons > 0)
754
+ summary.push(count(totalLessons, labels.lessonSingular, labels.lessonPlural));
755
+ const headingId = `${baseId}-heading`;
756
+ const Tag = `h${headingLevel}`;
757
+ function toggle(id) {
758
+ setOpen((prev) => {
759
+ const next = new Set(prev);
760
+ if (next.has(id)) next.delete(id);
761
+ else next.add(id);
762
+ return next;
763
+ });
764
+ }
765
+ return /* @__PURE__ */ jsxs6(
766
+ "section",
767
+ {
768
+ "data-slot": "course-syllabus",
769
+ "aria-labelledby": headingId,
770
+ className: cn8("space-y-4", className),
771
+ children: [
772
+ /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
773
+ /* @__PURE__ */ jsx8(
774
+ Tag,
775
+ {
776
+ id: headingId,
777
+ className: slotClassName("", "text-xl font-semibold", headingClassName),
778
+ children: labels.heading
779
+ }
780
+ ),
781
+ /* @__PURE__ */ jsx8("p", { "data-slot": "course-syllabus-summary", className: "text-sm text-muted-foreground", children: summary.join(SEPARATOR) })
782
+ ] }),
783
+ /* @__PURE__ */ jsx8("ol", { className: "flex list-none flex-col gap-2.5 p-0", children: modules.map((module, index) => {
784
+ const lessons = module.lessons ?? [];
785
+ const number = /* @__PURE__ */ jsx8(
786
+ "span",
787
+ {
788
+ "aria-hidden": "true",
789
+ className: "flex size-7 shrink-0 items-center justify-center rounded-full bg-muted text-sm font-semibold text-primary",
790
+ children: index + 1
791
+ }
792
+ );
793
+ if (lessons.length === 0) {
794
+ return /* @__PURE__ */ jsxs6(
795
+ "li",
796
+ {
797
+ "data-slot": "course-syllabus-module",
798
+ className: "flex items-center gap-3.5 rounded-lg border border-border bg-card px-4 py-3.5",
799
+ children: [
800
+ number,
801
+ /* @__PURE__ */ jsx8("span", { className: "font-semibold leading-snug", children: module.title })
802
+ ]
803
+ },
804
+ module.id
805
+ );
806
+ }
807
+ const isOpen = open.has(module.id);
808
+ const panelId = `${baseId}-module-${index}`;
809
+ const seconds = moduleSeconds(lessons);
810
+ const meta = [count(lessons.length, labels.lessonSingular, labels.lessonPlural)];
811
+ if (seconds !== null) meta.push(formatDuration(seconds, labels));
812
+ return /* @__PURE__ */ jsxs6(
813
+ "li",
814
+ {
815
+ "data-slot": "course-syllabus-module",
816
+ className: "rounded-lg border border-border bg-card",
817
+ children: [
818
+ /* @__PURE__ */ jsxs6(
819
+ "button",
820
+ {
821
+ type: "button",
822
+ "aria-expanded": isOpen,
823
+ "aria-controls": panelId,
824
+ onClick: () => toggle(module.id),
825
+ className: "flex w-full cursor-pointer items-center gap-3.5 rounded-lg px-4 py-3.5 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
826
+ children: [
827
+ number,
828
+ /* @__PURE__ */ jsxs6("span", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
829
+ /* @__PURE__ */ jsx8("span", { className: "font-semibold leading-snug", children: module.title }),
830
+ /* @__PURE__ */ jsx8("span", { className: "text-sm text-muted-foreground", children: meta.join(SEPARATOR) })
831
+ ] }),
832
+ /* @__PURE__ */ jsx8(
833
+ "span",
834
+ {
835
+ "aria-hidden": "true",
836
+ className: cn8(
837
+ "shrink-0 text-muted-foreground transition-transform motion-reduce:transition-none",
838
+ isOpen && "rotate-180"
839
+ ),
840
+ children: "\u25BE"
841
+ }
842
+ )
843
+ ]
844
+ }
845
+ ),
846
+ /* @__PURE__ */ jsx8(
847
+ "ol",
848
+ {
849
+ id: panelId,
850
+ hidden: !isOpen,
851
+ "data-slot": "course-syllabus-lessons",
852
+ className: "list-none space-y-2 border-t border-border px-4 py-3 pl-[3.75rem]",
853
+ children: lessons.map((lesson) => /* @__PURE__ */ jsxs6(
854
+ "li",
855
+ {
856
+ "data-slot": "course-syllabus-lesson",
857
+ className: "flex flex-wrap items-baseline gap-x-3 gap-y-1 text-sm",
858
+ children: [
859
+ /* @__PURE__ */ jsx8("span", { "data-slot": "course-syllabus-lesson-title", className: "flex-1", children: lesson.title }),
860
+ lesson.isFreePreview && /* @__PURE__ */ jsx8("span", { className: "rounded-full bg-muted px-2 py-0.5 text-xs font-medium", children: labels.freePreview }),
861
+ typeof lesson.durationSeconds === "number" && lesson.durationSeconds > 0 && /* @__PURE__ */ jsx8("span", { className: "text-muted-foreground tabular-nums", children: formatDuration(lesson.durationSeconds, labels) })
862
+ ]
863
+ },
864
+ lesson.id
865
+ ))
866
+ }
867
+ )
868
+ ]
869
+ },
870
+ module.id
871
+ );
872
+ }) })
873
+ ]
874
+ }
875
+ );
876
+ }
877
+
878
+ // src/components/data-request-form.tsx
879
+ import { useEffect as useEffect4, useId as useId3, useRef as useRef4, useState as useState7 } from "react";
880
+ import { cn as cn9 } from "@reblu/site-ui/utils";
693
881
  import {
694
882
  DATA_REQUEST_TYPES
695
883
  } from "@reblu/site-contracts";
696
- import { Fragment, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
884
+ import { Fragment, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
697
885
  var DATA_REQUEST_FIELD_LIMITS = Object.freeze({ name: 200, email: 320, details: 5e3 });
698
886
  var DEFAULT_DATA_REQUEST_FORM_LABELS = {
699
887
  requestTypeLabel: "Derecho que quieres ejercer",
@@ -719,7 +907,7 @@ var DEFAULT_DATA_REQUEST_FORM_LABELS = {
719
907
  nameRequired: "Indica tu nombre.",
720
908
  emailInvalid: "Introduce un email v\xE1lido.",
721
909
  consentRequired: "Debes aceptar el tratamiento de tus datos para gestionar la solicitud.",
722
- success: (deadline) => /* @__PURE__ */ jsxs6(Fragment, { children: [
910
+ success: (deadline) => /* @__PURE__ */ jsxs7(Fragment, { children: [
723
911
  "Hemos recibido tu solicitud. Te responderemos como m\xE1ximo el ",
724
912
  deadline,
725
913
  "."
@@ -768,16 +956,16 @@ function DataRequestForm({
768
956
  ...labels,
769
957
  requestTypes: { ...DEFAULT_DATA_REQUEST_FORM_LABELS.requestTypes, ...labels?.requestTypes }
770
958
  };
771
- const id = useId2();
772
- const [requestType, setRequestType] = useState6("");
773
- const [name, setName] = useState6("");
774
- const [email, setEmail] = useState6("");
775
- const [details, setDetails] = useState6("");
776
- const [consent, setConsent] = useState6(false);
777
- const [errors, setErrors] = useState6({});
778
- const [formError, setFormError] = useState6(null);
779
- const [submitting, setSubmitting] = useState6(false);
780
- const [ack, setAck] = useState6(null);
959
+ const id = useId3();
960
+ const [requestType, setRequestType] = useState7("");
961
+ const [name, setName] = useState7("");
962
+ const [email, setEmail] = useState7("");
963
+ const [details, setDetails] = useState7("");
964
+ const [consent, setConsent] = useState7(false);
965
+ const [errors, setErrors] = useState7({});
966
+ const [formError, setFormError] = useState7(null);
967
+ const [submitting, setSubmitting] = useState7(false);
968
+ const [ack, setAck] = useState7(null);
781
969
  const statusRef = useRef4(null);
782
970
  useEffect4(() => {
783
971
  if (ack) statusRef.current?.focus();
@@ -830,21 +1018,21 @@ function DataRequestForm({
830
1018
  dateStyle: "long",
831
1019
  timeStyle: "short"
832
1020
  }).format(new Date(ack.slaDueAt));
833
- return /* @__PURE__ */ jsx8(
1021
+ return /* @__PURE__ */ jsx9(
834
1022
  "div",
835
1023
  {
836
1024
  ref: statusRef,
837
1025
  tabIndex: -1,
838
1026
  role: "status",
839
1027
  "data-slot": "data-request-form-success",
840
- className: cn7("rounded-lg border border-border p-6 text-sm", className),
1028
+ className: cn9("rounded-lg border border-border p-6 text-sm", className),
841
1029
  children: t.success(deadline)
842
1030
  }
843
1031
  );
844
1032
  }
845
1033
  const errorId = (field) => errors[field] ? `${id}-${field}-error` : void 0;
846
- const fieldError = (field) => errors[field] ? /* @__PURE__ */ jsx8("p", { id: `${id}-${field}-error`, className: "text-xs text-destructive", children: errors[field] }) : null;
847
- return /* @__PURE__ */ jsxs6(
1034
+ const fieldError = (field) => errors[field] ? /* @__PURE__ */ jsx9("p", { id: `${id}-${field}-error`, className: "text-xs text-destructive", children: errors[field] }) : null;
1035
+ return /* @__PURE__ */ jsxs7(
848
1036
  "form",
849
1037
  {
850
1038
  noValidate: true,
@@ -852,11 +1040,11 @@ function DataRequestForm({
852
1040
  onFocusCapture: onInteract,
853
1041
  onPointerDown: onInteract,
854
1042
  "data-slot": "data-request-form",
855
- className: cn7("space-y-4", className),
1043
+ className: cn9("space-y-4", className),
856
1044
  children: [
857
- /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
858
- /* @__PURE__ */ jsx8("label", { htmlFor: `${id}-type`, className: "text-sm font-medium", children: t.requestTypeLabel }),
859
- /* @__PURE__ */ jsxs6(
1045
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1", children: [
1046
+ /* @__PURE__ */ jsx9("label", { htmlFor: `${id}-type`, className: "text-sm font-medium", children: t.requestTypeLabel }),
1047
+ /* @__PURE__ */ jsxs7(
860
1048
  "select",
861
1049
  {
862
1050
  id: `${id}-type`,
@@ -864,18 +1052,18 @@ function DataRequestForm({
864
1052
  onChange: (e) => setRequestType(e.target.value),
865
1053
  "aria-invalid": errors.requestType ? true : void 0,
866
1054
  "aria-describedby": errorId("requestType"),
867
- className: cn7(FIELD_CLASS, errors.requestType ? "border-destructive" : "border-border"),
1055
+ className: cn9(FIELD_CLASS, errors.requestType ? "border-destructive" : "border-border"),
868
1056
  children: [
869
- /* @__PURE__ */ jsx8("option", { value: "", children: t.requestTypePlaceholder }),
870
- requestTypes.map((type) => /* @__PURE__ */ jsx8("option", { value: type, children: t.requestTypes[type] }, type))
1057
+ /* @__PURE__ */ jsx9("option", { value: "", children: t.requestTypePlaceholder }),
1058
+ requestTypes.map((type) => /* @__PURE__ */ jsx9("option", { value: type, children: t.requestTypes[type] }, type))
871
1059
  ]
872
1060
  }
873
1061
  ),
874
1062
  fieldError("requestType")
875
1063
  ] }),
876
- /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
877
- /* @__PURE__ */ jsx8("label", { htmlFor: `${id}-name`, className: "text-sm font-medium", children: t.nameLabel }),
878
- /* @__PURE__ */ jsx8(
1064
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1", children: [
1065
+ /* @__PURE__ */ jsx9("label", { htmlFor: `${id}-name`, className: "text-sm font-medium", children: t.nameLabel }),
1066
+ /* @__PURE__ */ jsx9(
879
1067
  "input",
880
1068
  {
881
1069
  id: `${id}-name`,
@@ -886,14 +1074,14 @@ function DataRequestForm({
886
1074
  onChange: (e) => setName(e.target.value),
887
1075
  "aria-invalid": errors.name ? true : void 0,
888
1076
  "aria-describedby": errorId("name"),
889
- className: cn7(FIELD_CLASS, errors.name ? "border-destructive" : "border-border")
1077
+ className: cn9(FIELD_CLASS, errors.name ? "border-destructive" : "border-border")
890
1078
  }
891
1079
  ),
892
1080
  fieldError("name")
893
1081
  ] }),
894
- /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
895
- /* @__PURE__ */ jsx8("label", { htmlFor: `${id}-email`, className: "text-sm font-medium", children: t.emailLabel }),
896
- /* @__PURE__ */ jsx8(
1082
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1", children: [
1083
+ /* @__PURE__ */ jsx9("label", { htmlFor: `${id}-email`, className: "text-sm font-medium", children: t.emailLabel }),
1084
+ /* @__PURE__ */ jsx9(
897
1085
  "input",
898
1086
  {
899
1087
  id: `${id}-email`,
@@ -904,14 +1092,14 @@ function DataRequestForm({
904
1092
  onChange: (e) => setEmail(e.target.value),
905
1093
  "aria-invalid": errors.email ? true : void 0,
906
1094
  "aria-describedby": errorId("email"),
907
- className: cn7(FIELD_CLASS, errors.email ? "border-destructive" : "border-border")
1095
+ className: cn9(FIELD_CLASS, errors.email ? "border-destructive" : "border-border")
908
1096
  }
909
1097
  ),
910
1098
  fieldError("email")
911
1099
  ] }),
912
- /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
913
- /* @__PURE__ */ jsx8("label", { htmlFor: `${id}-details`, className: "text-sm font-medium", children: t.detailsLabel }),
914
- /* @__PURE__ */ jsx8(
1100
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1", children: [
1101
+ /* @__PURE__ */ jsx9("label", { htmlFor: `${id}-details`, className: "text-sm font-medium", children: t.detailsLabel }),
1102
+ /* @__PURE__ */ jsx9(
915
1103
  "textarea",
916
1104
  {
917
1105
  id: `${id}-details`,
@@ -920,13 +1108,13 @@ function DataRequestForm({
920
1108
  value: details,
921
1109
  onChange: (e) => setDetails(e.target.value),
922
1110
  placeholder: t.detailsPlaceholder,
923
- className: cn7(FIELD_CLASS, "border-border")
1111
+ className: cn9(FIELD_CLASS, "border-border")
924
1112
  }
925
1113
  )
926
1114
  ] }),
927
- /* @__PURE__ */ jsxs6("div", { className: "space-y-1", children: [
928
- /* @__PURE__ */ jsxs6("div", { className: "flex items-start gap-2", children: [
929
- /* @__PURE__ */ jsx8(
1115
+ /* @__PURE__ */ jsxs7("div", { className: "space-y-1", children: [
1116
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-start gap-2", children: [
1117
+ /* @__PURE__ */ jsx9(
930
1118
  "input",
931
1119
  {
932
1120
  id: `${id}-consent`,
@@ -938,12 +1126,12 @@ function DataRequestForm({
938
1126
  className: "mt-1"
939
1127
  }
940
1128
  ),
941
- /* @__PURE__ */ jsx8("label", { htmlFor: `${id}-consent`, className: "text-sm text-foreground/80", children: t.consent })
1129
+ /* @__PURE__ */ jsx9("label", { htmlFor: `${id}-consent`, className: "text-sm text-foreground/80", children: t.consent })
942
1130
  ] }),
943
1131
  fieldError("consent")
944
1132
  ] }),
945
- formError && /* @__PURE__ */ jsx8("p", { role: "alert", className: "text-sm text-destructive", children: formError }),
946
- /* @__PURE__ */ jsx8(
1133
+ formError && /* @__PURE__ */ jsx9("p", { role: "alert", className: "text-sm text-destructive", children: formError }),
1134
+ /* @__PURE__ */ jsx9(
947
1135
  "button",
948
1136
  {
949
1137
  type: "submit",
@@ -960,8 +1148,10 @@ export {
960
1148
  AddToCartButton,
961
1149
  CartIcon,
962
1150
  Collection,
1151
+ CourseSyllabus,
963
1152
  DATA_REQUEST_FIELD_LIMITS,
964
1153
  DATA_REQUEST_TYPES,
1154
+ DEFAULT_COURSE_SYLLABUS_LABELS,
965
1155
  DEFAULT_DATA_REQUEST_FORM_LABELS,
966
1156
  DEFAULT_PRODUCT_CAROUSEL_LABELS,
967
1157
  DataRequestForm,