{"version":3,"file":"QuoteWidget-CJ8MAZO_.mjs","names":[],"sources":["../../widgets/src/widgets/QuoteWidget.tsx"],"sourcesContent":["import type {\n  WidgetPropertySchema,\n  QuoteListItem,\n} from \"@fluid-app/portal-core/registries\";\nimport type { ComponentProps } from \"react\";\nimport type React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport {\n  getBorderColorField,\n  getBorderRadiusField,\n  getBorderWidthField,\n  getColorField,\n  getFontSizeField,\n  getPaddingField,\n  borderWidthClasses,\n  borderColorClasses,\n} from \"../core/fields\";\nimport type {\n  BackgroundValue,\n  BorderRadiusOptions,\n  BorderWidthOptions,\n  ColorOptions,\n  FontSizeOptions,\n  PaddingOptions,\n} from \"@fluid-app/portal-core/types\";\nimport { useWidgetPreviewContext } from \"@fluid-app/portal-react/data-sources/preview-context\";\nimport {\n  AlignCenter,\n  AlignLeft,\n  AlignRight,\n  ChevronLeft,\n  ChevronRight,\n  Quote,\n} from \"lucide-react\";\n\ntype TextAlignment = \"left\" | \"center\" | \"right\";\ntype RotationMode = \"carousel\" | \"daily\";\n\nconst MS_PER_DAY = 86_400_000;\n\nconst textAlignmentClasses: Record<TextAlignment, string> = {\n  left: \"text-left\",\n  center: \"text-center\",\n  right: \"text-right\",\n} as const;\n\n// The decorative quote mark follows the text alignment via margin-auto.\nconst markAlignmentClasses: Record<TextAlignment, string> = {\n  left: \"mr-auto\",\n  center: \"mx-auto\",\n  right: \"ml-auto\",\n} as const;\n\n// FontSizeOptions like \"md\" don't map to a real Tailwind class via\n// `text-${size}` (there is no `text-md`), so resolve through a table.\nconst fontSizeClasses: Record<FontSizeOptions, string> = {\n  \"2xl\": \"text-2xl\",\n  xl: \"text-xl\",\n  lg: \"text-lg\",\n  md: \"text-base\",\n  sm: \"text-sm\",\n  xs: \"text-xs\",\n};\n\n// A text token that matches the surface renders invisibly. Fall back to a token\n// that actually contrasts: \"background\" when the surface itself is \"foreground\",\n// otherwise \"foreground\" (so a foreground-on-foreground pick stays legible too).\nfunction readableOn(color: ColorOptions, surface: ColorOptions): ColorOptions {\n  if (color !== surface) return color;\n  return surface === \"foreground\" ? \"background\" : \"foreground\";\n}\n\ntype QuoteWidgetProps = ComponentProps<\"div\"> & {\n  // One or many quotes (edited as a list in the panel)\n  quotes?: QuoteListItem[];\n\n  // Legacy single-quote props — kept so widgets saved before the list still\n  // render. When `quotes` is empty these become the single quote.\n  quote?: string;\n  attribution?: string;\n  attributionRole?: string;\n\n  // Shared quote styling\n  quoteColor?: ColorOptions;\n  quoteFontSize?: FontSizeOptions;\n  attributionColor?: ColorOptions;\n  accentColor?: ColorOptions;\n\n  // Rotation (only applies when there is more than one quote)\n  rotation?: RotationMode;\n  autoScrollInterval?: number;\n  showArrows?: boolean;\n  showDots?: boolean;\n\n  // Layout / container styling\n  alignment?: TextAlignment;\n  background?: BackgroundValue;\n  padding?: PaddingOptions;\n  borderRadius?: BorderRadiusOptions;\n  borderWidth?: BorderWidthOptions;\n  borderColor?: ColorOptions;\n};\n\nexport function QuoteWidget({\n  quotes,\n  quote,\n  attribution,\n  attributionRole,\n  quoteColor = \"foreground\",\n  quoteFontSize = \"xl\",\n  attributionColor = \"foreground\",\n  accentColor = \"primary\",\n  rotation = \"carousel\",\n  autoScrollInterval = 6500,\n  showArrows = true,\n  showDots = true,\n  alignment = \"left\",\n  background = {\n    type: \"solid\",\n    color: \"muted\",\n  },\n  padding = 8,\n  borderRadius = \"lg\",\n  borderWidth = \"none\",\n  borderColor = \"muted\",\n  className,\n  ...props\n}: QuoteWidgetProps): React.JSX.Element {\n  const { isPreview } = useWidgetPreviewContext();\n\n  // Resolve the list of quotes to show: the `quotes` array, or the legacy\n  // single-quote props, or a placeholder — always at least one.\n  const listed = (quotes ?? []).filter((q) => !!q && q.quote.trim().length > 0);\n  let resolved: QuoteListItem[];\n  if (listed.length > 0) {\n    resolved = listed;\n  } else {\n    const fallback: QuoteListItem = {\n      quote: quote?.trim() ? quote : \"Add an inspiring quote here.\",\n    };\n    if (attribution) fallback.attribution = attribution;\n    if (attributionRole) fallback.role = attributionRole;\n    resolved = [fallback];\n  }\n  const count = resolved.length;\n\n  const [manualIndex, setManualIndex] = useState(0);\n  const goNext = useCallback(() => setManualIndex((i) => i + 1), []);\n  const goPrev = useCallback(() => setManualIndex((i) => i - 1), []);\n  // Bump-only state: forces a re-render so daily mode advances after midnight.\n  const [, setDayTick] = useState(0);\n\n  // Live \"quote of the day\" picks by the calendar day; carousel + editing use\n  // the manual/timed index. A single quote never rotates. Derive the day from\n  // the viewer's *local* calendar date (not the raw Unix timestamp) so the\n  // quote rolls over at their local midnight rather than UTC midnight.\n  const now = new Date();\n  const localDay = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate());\n  const dayIndex = Math.floor(localDay / MS_PER_DAY) % count;\n  const liveDaily = rotation === \"daily\" && !isPreview;\n  const activeIndex =\n    count <= 1\n      ? 0\n      : liveDaily\n        ? dayIndex\n        : ((manualIndex % count) + count) % count;\n\n  const autoScroll = rotation === \"carousel\" && !isPreview && count > 1;\n  useEffect(() => {\n    if (!autoScroll) return;\n    const id = setInterval(goNext, Math.max(1500, autoScrollInterval));\n    return () => clearInterval(id);\n  }, [autoScroll, autoScrollInterval, goNext]);\n\n  // In live daily mode the day index is only read at render, so a portal left\n  // open across midnight would keep showing yesterday's quote. Schedule a\n  // re-render at the next local midnight so it rolls over on time rather than\n  // lagging a polling interval, then reschedule for the day after. Effects don't\n  // run during SSR, so tests (renderToStaticMarkup) are unaffected.\n  useEffect(() => {\n    if (!liveDaily) return;\n    let timer: ReturnType<typeof setTimeout> | undefined;\n    const scheduleRollover = () => {\n      const current = new Date();\n      const nextMidnight = new Date(\n        current.getFullYear(),\n        current.getMonth(),\n        current.getDate() + 1,\n      ).getTime();\n      timer = setTimeout(() => {\n        setDayTick((t) => t + 1);\n        scheduleRollover();\n      }, nextMidnight - current.getTime());\n    };\n    scheduleRollover();\n    return () => clearTimeout(timer);\n  }, [liveDaily]);\n\n  const active = resolved[activeIndex];\n\n  // Any text token that matches the background renders invisibly (e.g. a muted\n  // quote or name on the muted default surface, or foreground text on a\n  // foreground surface). Fall back to a contrasting token so the quote body and\n  // attribution stay legible.\n  const backgroundColor = background.color || \"muted\";\n  const bodyColor = readableOn(quoteColor, backgroundColor);\n  const nameColor = readableOn(attributionColor, backgroundColor);\n  // Manual controls appear when there is more than one quote to move between —\n  // for viewers in carousel mode, and in either mode while editing.\n  const navigable = count > 1 && (rotation === \"carousel\" || isPreview);\n  const backgroundImage =\n    (background.resource?.image_url || background.resource?.imageUrl) &&\n    background.type === \"image\"\n      ? `url(${background.resource.image_url || background.resource.imageUrl})`\n      : \"none\";\n\n  return (\n    <figure\n      className={`relative flex flex-col rounded-${borderRadius} ${borderWidthClasses[borderWidth]} ${borderWidth !== \"none\" ? borderColorClasses[borderColor] : \"\"} bg-${backgroundColor} p-${padding} ${textAlignmentClasses[alignment]} ${className ?? \"\"}`}\n      style={{ backgroundImage }}\n      {...props}\n    >\n      {/* Decorative quote mark — a soft accent anchor, not read by SR. */}\n      <Quote\n        className={`mb-3 block size-9 fill-${accentColor}/15 text-${accentColor}/40 ${markAlignmentClasses[alignment]}`}\n        aria-hidden\n      />\n\n      <blockquote\n        className={`${fontSizeClasses[quoteFontSize]} font-header leading-relaxed tracking-[-0.01em] text-pretty text-${bodyColor}`}\n      >\n        {active?.quote}\n      </blockquote>\n\n      {active?.attribution && (\n        <figcaption className=\"mt-5\">\n          <span\n            className={`inline-block h-0.5 w-8 rounded-full bg-${accentColor}/60 align-middle`}\n            aria-hidden\n          />\n          <span\n            className={`ml-3 align-middle text-sm font-semibold tracking-tight text-${nameColor}`}\n          >\n            {active.attribution}\n          </span>\n          {active.role && (\n            <span className={`mt-1 block text-xs text-${nameColor}/60`}>\n              {active.role}\n            </span>\n          )}\n        </figcaption>\n      )}\n\n      {navigable && showArrows && (\n        <>\n          <button\n            type=\"button\"\n            aria-label=\"Previous quote\"\n            onClick={goPrev}\n            className={`absolute top-1/2 left-2 flex size-8 -translate-y-1/2 items-center justify-center rounded-full bg-${backgroundColor}/80 text-${accentColor} shadow-sm transition-colors hover:bg-${backgroundColor}`}\n          >\n            <ChevronLeft className=\"size-4\" aria-hidden />\n          </button>\n          <button\n            type=\"button\"\n            aria-label=\"Next quote\"\n            onClick={goNext}\n            className={`absolute top-1/2 right-2 flex size-8 -translate-y-1/2 items-center justify-center rounded-full bg-${backgroundColor}/80 text-${accentColor} shadow-sm transition-colors hover:bg-${backgroundColor}`}\n          >\n            <ChevronRight className=\"size-4\" aria-hidden />\n          </button>\n        </>\n      )}\n\n      {navigable && showDots && (\n        <div className=\"mt-4 flex items-center justify-center gap-1.5\">\n          {resolved.map((_item, i) => (\n            <button\n              key={i}\n              type=\"button\"\n              aria-label={`Go to quote ${i + 1}`}\n              aria-current={i === activeIndex}\n              onClick={() => setManualIndex(i)}\n              className={`h-1.5 rounded-full transition-all ${\n                i === activeIndex\n                  ? `w-4 bg-${accentColor}`\n                  : `w-1.5 bg-${accentColor}/30 hover:bg-${accentColor}/50`\n              }`}\n            />\n          ))}\n        </div>\n      )}\n    </figure>\n  );\n}\n\nexport const quoteWidgetPropertySchema: WidgetPropertySchema = {\n  widgetType: \"QuoteWidget\",\n  displayName: \"Quote\",\n  tabsConfig: [{ id: \"content\", label: \"Content\" }],\n  fields: [\n    // Quotes group — the editable list\n    {\n      key: \"quotes\",\n      label: \"Quotes\",\n      type: \"quoteList\",\n      description: \"One or many quotes. Add more to rotate between them.\",\n      defaultValue: [{ quote: \"Add an inspiring quote here.\" }],\n      tab: \"content\",\n      group: \"Quotes\",\n    },\n    // Rotation group (applies when there is more than one quote)\n    {\n      key: \"rotation\",\n      label: \"Rotation\",\n      type: \"select\",\n      description:\n        \"With multiple quotes: auto-scroll carousel, or one per day (quote of the day)\",\n      options: [\n        { label: \"Carousel (auto-scroll)\", value: \"carousel\" },\n        { label: \"Quote of the day (daily)\", value: \"daily\" },\n      ],\n      defaultValue: \"carousel\",\n      tab: \"content\",\n      group: \"Rotation\",\n    },\n    {\n      key: \"autoScrollInterval\",\n      label: \"Auto-Scroll Interval (ms)\",\n      type: \"number\",\n      description: \"How long each quote shows before advancing\",\n      defaultValue: 6500,\n      min: 1500,\n      max: 30000,\n      tab: \"content\",\n      group: \"Rotation\",\n      requiresKeyValue: { key: \"rotation\", value: \"carousel\" },\n    },\n    {\n      key: \"showArrows\",\n      label: \"Show Arrows\",\n      type: \"boolean\",\n      description: \"Show previous / next arrows\",\n      defaultValue: true,\n      tab: \"content\",\n      group: \"Rotation\",\n    },\n    {\n      key: \"showDots\",\n      label: \"Show Dots\",\n      type: \"boolean\",\n      description: \"Show the position dots\",\n      defaultValue: true,\n      tab: \"content\",\n      group: \"Rotation\",\n    },\n    // Style group\n    getFontSizeField({\n      key: \"quoteFontSize\",\n      label: \"Quote Font Size\",\n      description: \"Font size for the quote\",\n      defaultValue: \"xl\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    getColorField({\n      key: \"quoteColor\",\n      label: \"Quote Color\",\n      description: \"The color of the quote text\",\n      defaultValue: \"foreground\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    getColorField({\n      key: \"attributionColor\",\n      label: \"Attribution Color\",\n      description:\n        \"The color of the name and role — keep it readable on the background\",\n      defaultValue: \"foreground\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    getColorField({\n      key: \"accentColor\",\n      label: \"Accent Color\",\n      description: \"Quote mark, attribution rule, arrows and active dot\",\n      defaultValue: \"primary\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    {\n      key: \"alignment\",\n      label: \"Alignment\",\n      type: \"buttonGroup\",\n      description: \"Text alignment\",\n      options: [\n        { icon: AlignLeft, ariaLabel: \"Align left\", value: \"left\" },\n        { icon: AlignCenter, ariaLabel: \"Align center\", value: \"center\" },\n        { icon: AlignRight, ariaLabel: \"Align right\", value: \"right\" },\n      ],\n      defaultValue: \"left\",\n      tab: \"content\",\n      group: \"Style\",\n    },\n    {\n      type: \"background\",\n      key: \"background\",\n      label: \"Background\",\n      description: \"Background for the quote container\",\n      defaultValue: { type: \"solid\", color: \"muted\" },\n      tab: \"content\",\n      group: \"Style\",\n    },\n    getPaddingField({\n      key: \"padding\",\n      label: \"Padding\",\n      description: \"The padding of the quote container\",\n      defaultValue: 8,\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    getBorderRadiusField({\n      key: \"borderRadius\",\n      label: \"Border Radius\",\n      description: \"The border radius of the quote container\",\n      defaultValue: \"lg\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    getBorderWidthField({\n      key: \"borderWidth\",\n      label: \"Border Width\",\n      description: \"Width of the container border\",\n      defaultValue: \"none\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n    getBorderColorField({\n      key: \"borderColor\",\n      label: \"Border Color\",\n      description: \"Color of the container border\",\n      defaultValue: \"muted\",\n      tab: \"content\",\n      group: \"Style\",\n    }),\n  ],\n};\n"],"mappings":"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"}