pixelon 0.7.4 → 0.8.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.
@@ -7,6 +7,7 @@ export interface ServiceShortcut {
7
7
  /** A dónde llevar. Alternativa a `prompt`. */
8
8
  route?: string;
9
9
  prompt?: string;
10
+ newChat?: boolean;
10
11
  icon?: 'map' | 'list' | 'tow' | 'search' | 'user' | 'chat' | 'enroll';
11
12
  }
12
13
  export interface ServiceShortcutsProps {
@@ -101,6 +101,13 @@ export interface ChatConfig {
101
101
  message: string;
102
102
  type?: 'success' | 'warning' | 'error' | 'info';
103
103
  };
104
+ /**
105
+ * SPEC-157 — tema visual del chat. `'dark'`/`'light'` fuerzan uno explícito (se pintan como
106
+ * atributo `data-theme` en la raíz del chat); `'system'` no fuerza nada y deja que
107
+ * `prefers-color-scheme` del sistema operativo decida. Default `'dark'`: mientras el host no
108
+ * tenga dónde guardar la preferencia de cada usuario (ver SPEC-157 Fase 3), el chat abre oscuro.
109
+ */
110
+ theme?: 'light' | 'dark' | 'system';
104
111
  }
105
112
  export declare const CHAT_CONFIG_DEFAULTS: ChatConfig;
106
113
  export interface ChatConfigProviderProps {
package/dist/index.esm.js CHANGED
@@ -2495,7 +2495,8 @@ const CHAT_CONFIG_DEFAULTS = {
2495
2495
  showMicrophoneButton: true,
2496
2496
  placeholderText: "Type a message...",
2497
2497
  enableStreamingEffect: false,
2498
- contained: false
2498
+ contained: false,
2499
+ theme: "dark"
2499
2500
  };
2500
2501
  const ChatConfigContext = createContext(CHAT_CONFIG_DEFAULTS);
2501
2502
  const ChatConfigProvider = ({ value, children }) => /* @__PURE__ */ jsx(ChatConfigContext.Provider, { value, children });
@@ -15637,6 +15638,33 @@ const DEFAULT_HEIGHT$1 = 320;
15637
15638
  const SINGLE_POINT_ZOOM = 15;
15638
15639
  const FOLLOW_EDGE_RATIO = 0.2;
15639
15640
  const HEADING_STEP = 5;
15641
+ const MAPA_ESTILO_OSCURO = [
15642
+ { elementType: "geometry", stylers: [{ color: "#212121" }] },
15643
+ { elementType: "labels.icon", stylers: [{ visibility: "off" }] },
15644
+ { elementType: "labels.text.fill", stylers: [{ color: "#757575" }] },
15645
+ { elementType: "labels.text.stroke", stylers: [{ color: "#212121" }] },
15646
+ { featureType: "administrative", elementType: "geometry", stylers: [{ color: "#757575" }] },
15647
+ { featureType: "administrative.country", elementType: "labels.text.fill", stylers: [{ color: "#9e9e9e" }] },
15648
+ { featureType: "administrative.land_parcel", stylers: [{ visibility: "off" }] },
15649
+ { featureType: "administrative.locality", elementType: "labels.text.fill", stylers: [{ color: "#bdbdbd" }] },
15650
+ { featureType: "poi", elementType: "labels.text.fill", stylers: [{ color: "#757575" }] },
15651
+ { featureType: "poi.park", elementType: "geometry", stylers: [{ color: "#181818" }] },
15652
+ { featureType: "poi.park", elementType: "labels.text.fill", stylers: [{ color: "#616161" }] },
15653
+ { featureType: "poi.park", elementType: "labels.text.stroke", stylers: [{ color: "#1b1b1b" }] },
15654
+ { featureType: "road", elementType: "geometry.fill", stylers: [{ color: "#2c2c2c" }] },
15655
+ { featureType: "road", elementType: "labels.text.fill", stylers: [{ color: "#8a8a8a" }] },
15656
+ { featureType: "road.arterial", elementType: "geometry", stylers: [{ color: "#373737" }] },
15657
+ { featureType: "road.highway", elementType: "geometry", stylers: [{ color: "#3c3c3c" }] },
15658
+ { featureType: "road.highway.controlled_access", elementType: "geometry", stylers: [{ color: "#4e4e4e" }] },
15659
+ { featureType: "road.local", elementType: "labels.text.fill", stylers: [{ color: "#616161" }] },
15660
+ { featureType: "transit", elementType: "labels.text.fill", stylers: [{ color: "#757575" }] },
15661
+ { featureType: "water", elementType: "geometry", stylers: [{ color: "#000000" }] },
15662
+ { featureType: "water", elementType: "labels.text.fill", stylers: [{ color: "#3d3d3d" }] }
15663
+ ];
15664
+ const MAPA_ESTILO_CLARO = [];
15665
+ function leerEstiloDelTema() {
15666
+ return document.body.getAttribute("data-theme") === "dark" ? MAPA_ESTILO_OSCURO : MAPA_ESTILO_CLARO;
15667
+ }
15640
15668
  const SMOOTHING = 1.25;
15641
15669
  function moveMarker(entry, to, duration) {
15642
15670
  if (entry.raf) cancelAnimationFrame(entry.raf);
@@ -15727,13 +15755,22 @@ const MapView = ({
15727
15755
  zoom,
15728
15756
  mapTypeControl: false,
15729
15757
  streetViewControl: false,
15730
- fullscreenControl: false
15758
+ fullscreenControl: false,
15759
+ styles: leerEstiloDelTema()
15731
15760
  });
15732
15761
  mapRef.current.addListener("dragstart", () => {
15733
15762
  followSuspendedRef.current = true;
15734
15763
  });
15735
15764
  setMapReady(true);
15736
15765
  }, [status]);
15766
+ useEffect(() => {
15767
+ if (!mapReady || !mapRef.current) return;
15768
+ const observer = new MutationObserver(() => {
15769
+ mapRef.current?.setOptions({ styles: leerEstiloDelTema() });
15770
+ });
15771
+ observer.observe(document.body, { attributes: true, attributeFilter: ["data-theme"] });
15772
+ return () => observer.disconnect();
15773
+ }, [mapReady]);
15737
15774
  useEffect(() => {
15738
15775
  if (!mapReady || !mapRef.current) return;
15739
15776
  const maps = window.google.maps;
@@ -17035,7 +17072,8 @@ const ServiceShortcuts = ({
17035
17072
  onClick: () => {
17036
17073
  if (elegido) return;
17037
17074
  onSelect?.(o.id);
17038
- if (o.prompt) eventBus?.emit(CHAT_EVENT.SEND_MESSAGE, { content: o.prompt });
17075
+ if (o.newChat) eventBus?.emit(CHAT_EVENT.NEW_CHAT, null);
17076
+ else if (o.prompt) eventBus?.emit(CHAT_EVENT.SEND_MESSAGE, { content: o.prompt });
17039
17077
  else if (o.route) eventBus?.emit(CHAT_EVENT.NAVIGATE, { route: o.route });
17040
17078
  },
17041
17079
  children: [
@@ -19997,7 +20035,34 @@ const Chat = ({
19997
20035
  messages,
19998
20036
  showThinking
19999
20037
  });
20000
- const { showHeader, showCloseButton, headerTitle, headerAvatarSrc, showAttachmentButton, showMicrophoneButton, placeholderText, enableStreamingEffect, contained } = resolvedConfig;
20038
+ const { showHeader, showCloseButton, headerTitle, headerAvatarSrc, showAttachmentButton, showMicrophoneButton, placeholderText, enableStreamingEffect, contained, theme } = resolvedConfig;
20039
+ const dataTheme = theme === "system" ? void 0 : theme;
20040
+ useEffect(() => {
20041
+ const previousTheme = document.body.getAttribute("data-theme");
20042
+ const previousLumiTheme = document.body.getAttribute("data-lumi-theme");
20043
+ if (dataTheme) {
20044
+ document.body.setAttribute("data-theme", dataTheme);
20045
+ } else {
20046
+ document.body.removeAttribute("data-theme");
20047
+ }
20048
+ if (dataTheme === "dark") {
20049
+ document.body.setAttribute("data-lumi-theme", "dark");
20050
+ } else {
20051
+ document.body.removeAttribute("data-lumi-theme");
20052
+ }
20053
+ return () => {
20054
+ if (previousTheme === null) {
20055
+ document.body.removeAttribute("data-theme");
20056
+ } else {
20057
+ document.body.setAttribute("data-theme", previousTheme);
20058
+ }
20059
+ if (previousLumiTheme === null) {
20060
+ document.body.removeAttribute("data-lumi-theme");
20061
+ } else {
20062
+ document.body.setAttribute("data-lumi-theme", previousLumiTheme);
20063
+ }
20064
+ };
20065
+ }, [dataTheme]);
20001
20066
  const streamedMessages = useStreamingMessage({ messages, enabled: enableStreamingEffect });
20002
20067
  const messageGroups = groupMessagesByDate(streamedMessages);
20003
20068
  const headerSubtitle = dynamicSubtitle !== void 0 ? dynamicSubtitle : resolvedConfig.headerSubtitle;
@@ -20009,7 +20074,7 @@ const Chat = ({
20009
20074
  // SPEC-009 — lo lee el SCSS para no reservar el borde inferior mientras el teclado tapa.
20010
20075
  isKeyboardOpen ? `${COMPONENT_PREFIX$1}layout--keyboard` : ""
20011
20076
  ].filter(Boolean).join(" ");
20012
- return /* @__PURE__ */ jsx(ChatConfigProvider, { value: resolvedConfig, children: /* @__PURE__ */ jsxs("div", { className: layoutClasses, ref: layoutRef, children: [
20077
+ return /* @__PURE__ */ jsx(ChatConfigProvider, { value: resolvedConfig, children: /* @__PURE__ */ jsxs("div", { className: layoutClasses, ref: layoutRef, "data-theme": dataTheme, children: [
20013
20078
  showHeader && /* @__PURE__ */ jsx("header", { className: `${COMPONENT_PREFIX$1}header`, children: /* @__PURE__ */ jsx(
20014
20079
  ChatHeader,
20015
20080
  {
package/dist/index.js CHANGED
@@ -2516,7 +2516,8 @@ const CHAT_CONFIG_DEFAULTS = {
2516
2516
  showMicrophoneButton: true,
2517
2517
  placeholderText: "Type a message...",
2518
2518
  enableStreamingEffect: false,
2519
- contained: false
2519
+ contained: false,
2520
+ theme: "dark"
2520
2521
  };
2521
2522
  const ChatConfigContext = React.createContext(CHAT_CONFIG_DEFAULTS);
2522
2523
  const ChatConfigProvider = ({ value, children }) => /* @__PURE__ */ jsxRuntime.jsx(ChatConfigContext.Provider, { value, children });
@@ -15658,6 +15659,33 @@ const DEFAULT_HEIGHT$1 = 320;
15658
15659
  const SINGLE_POINT_ZOOM = 15;
15659
15660
  const FOLLOW_EDGE_RATIO = 0.2;
15660
15661
  const HEADING_STEP = 5;
15662
+ const MAPA_ESTILO_OSCURO = [
15663
+ { elementType: "geometry", stylers: [{ color: "#212121" }] },
15664
+ { elementType: "labels.icon", stylers: [{ visibility: "off" }] },
15665
+ { elementType: "labels.text.fill", stylers: [{ color: "#757575" }] },
15666
+ { elementType: "labels.text.stroke", stylers: [{ color: "#212121" }] },
15667
+ { featureType: "administrative", elementType: "geometry", stylers: [{ color: "#757575" }] },
15668
+ { featureType: "administrative.country", elementType: "labels.text.fill", stylers: [{ color: "#9e9e9e" }] },
15669
+ { featureType: "administrative.land_parcel", stylers: [{ visibility: "off" }] },
15670
+ { featureType: "administrative.locality", elementType: "labels.text.fill", stylers: [{ color: "#bdbdbd" }] },
15671
+ { featureType: "poi", elementType: "labels.text.fill", stylers: [{ color: "#757575" }] },
15672
+ { featureType: "poi.park", elementType: "geometry", stylers: [{ color: "#181818" }] },
15673
+ { featureType: "poi.park", elementType: "labels.text.fill", stylers: [{ color: "#616161" }] },
15674
+ { featureType: "poi.park", elementType: "labels.text.stroke", stylers: [{ color: "#1b1b1b" }] },
15675
+ { featureType: "road", elementType: "geometry.fill", stylers: [{ color: "#2c2c2c" }] },
15676
+ { featureType: "road", elementType: "labels.text.fill", stylers: [{ color: "#8a8a8a" }] },
15677
+ { featureType: "road.arterial", elementType: "geometry", stylers: [{ color: "#373737" }] },
15678
+ { featureType: "road.highway", elementType: "geometry", stylers: [{ color: "#3c3c3c" }] },
15679
+ { featureType: "road.highway.controlled_access", elementType: "geometry", stylers: [{ color: "#4e4e4e" }] },
15680
+ { featureType: "road.local", elementType: "labels.text.fill", stylers: [{ color: "#616161" }] },
15681
+ { featureType: "transit", elementType: "labels.text.fill", stylers: [{ color: "#757575" }] },
15682
+ { featureType: "water", elementType: "geometry", stylers: [{ color: "#000000" }] },
15683
+ { featureType: "water", elementType: "labels.text.fill", stylers: [{ color: "#3d3d3d" }] }
15684
+ ];
15685
+ const MAPA_ESTILO_CLARO = [];
15686
+ function leerEstiloDelTema() {
15687
+ return document.body.getAttribute("data-theme") === "dark" ? MAPA_ESTILO_OSCURO : MAPA_ESTILO_CLARO;
15688
+ }
15661
15689
  const SMOOTHING = 1.25;
15662
15690
  function moveMarker(entry, to, duration) {
15663
15691
  if (entry.raf) cancelAnimationFrame(entry.raf);
@@ -15748,13 +15776,22 @@ const MapView = ({
15748
15776
  zoom,
15749
15777
  mapTypeControl: false,
15750
15778
  streetViewControl: false,
15751
- fullscreenControl: false
15779
+ fullscreenControl: false,
15780
+ styles: leerEstiloDelTema()
15752
15781
  });
15753
15782
  mapRef.current.addListener("dragstart", () => {
15754
15783
  followSuspendedRef.current = true;
15755
15784
  });
15756
15785
  setMapReady(true);
15757
15786
  }, [status]);
15787
+ React.useEffect(() => {
15788
+ if (!mapReady || !mapRef.current) return;
15789
+ const observer = new MutationObserver(() => {
15790
+ mapRef.current?.setOptions({ styles: leerEstiloDelTema() });
15791
+ });
15792
+ observer.observe(document.body, { attributes: true, attributeFilter: ["data-theme"] });
15793
+ return () => observer.disconnect();
15794
+ }, [mapReady]);
15758
15795
  React.useEffect(() => {
15759
15796
  if (!mapReady || !mapRef.current) return;
15760
15797
  const maps = window.google.maps;
@@ -17056,7 +17093,8 @@ const ServiceShortcuts = ({
17056
17093
  onClick: () => {
17057
17094
  if (elegido) return;
17058
17095
  onSelect?.(o.id);
17059
- if (o.prompt) eventBus?.emit(CHAT_EVENT.SEND_MESSAGE, { content: o.prompt });
17096
+ if (o.newChat) eventBus?.emit(CHAT_EVENT.NEW_CHAT, null);
17097
+ else if (o.prompt) eventBus?.emit(CHAT_EVENT.SEND_MESSAGE, { content: o.prompt });
17060
17098
  else if (o.route) eventBus?.emit(CHAT_EVENT.NAVIGATE, { route: o.route });
17061
17099
  },
17062
17100
  children: [
@@ -20018,7 +20056,34 @@ const Chat = ({
20018
20056
  messages,
20019
20057
  showThinking
20020
20058
  });
20021
- const { showHeader, showCloseButton, headerTitle, headerAvatarSrc, showAttachmentButton, showMicrophoneButton, placeholderText, enableStreamingEffect, contained } = resolvedConfig;
20059
+ const { showHeader, showCloseButton, headerTitle, headerAvatarSrc, showAttachmentButton, showMicrophoneButton, placeholderText, enableStreamingEffect, contained, theme } = resolvedConfig;
20060
+ const dataTheme = theme === "system" ? void 0 : theme;
20061
+ React.useEffect(() => {
20062
+ const previousTheme = document.body.getAttribute("data-theme");
20063
+ const previousLumiTheme = document.body.getAttribute("data-lumi-theme");
20064
+ if (dataTheme) {
20065
+ document.body.setAttribute("data-theme", dataTheme);
20066
+ } else {
20067
+ document.body.removeAttribute("data-theme");
20068
+ }
20069
+ if (dataTheme === "dark") {
20070
+ document.body.setAttribute("data-lumi-theme", "dark");
20071
+ } else {
20072
+ document.body.removeAttribute("data-lumi-theme");
20073
+ }
20074
+ return () => {
20075
+ if (previousTheme === null) {
20076
+ document.body.removeAttribute("data-theme");
20077
+ } else {
20078
+ document.body.setAttribute("data-theme", previousTheme);
20079
+ }
20080
+ if (previousLumiTheme === null) {
20081
+ document.body.removeAttribute("data-lumi-theme");
20082
+ } else {
20083
+ document.body.setAttribute("data-lumi-theme", previousLumiTheme);
20084
+ }
20085
+ };
20086
+ }, [dataTheme]);
20022
20087
  const streamedMessages = useStreamingMessage({ messages, enabled: enableStreamingEffect });
20023
20088
  const messageGroups = groupMessagesByDate(streamedMessages);
20024
20089
  const headerSubtitle = dynamicSubtitle !== void 0 ? dynamicSubtitle : resolvedConfig.headerSubtitle;
@@ -20030,7 +20095,7 @@ const Chat = ({
20030
20095
  // SPEC-009 — lo lee el SCSS para no reservar el borde inferior mientras el teclado tapa.
20031
20096
  isKeyboardOpen ? `${COMPONENT_PREFIX$1}layout--keyboard` : ""
20032
20097
  ].filter(Boolean).join(" ");
20033
- return /* @__PURE__ */ jsxRuntime.jsx(ChatConfigProvider, { value: resolvedConfig, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: layoutClasses, ref: layoutRef, children: [
20098
+ return /* @__PURE__ */ jsxRuntime.jsx(ChatConfigProvider, { value: resolvedConfig, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: layoutClasses, ref: layoutRef, "data-theme": dataTheme, children: [
20034
20099
  showHeader && /* @__PURE__ */ jsxRuntime.jsx("header", { className: `${COMPONENT_PREFIX$1}header`, children: /* @__PURE__ */ jsxRuntime.jsx(
20035
20100
  ChatHeader,
20036
20101
  {