@devslab/site-kit 0.15.0 → 0.16.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.
@@ -1,6 +1,6 @@
1
- import { createComponent, escape, mergeProps, ssr, ssrAttribute, ssrElement, ssrHydrationKey } from "solid-js/web";
2
- import { For, Show, createMemo, createSignal, createUniqueId, onMount } from "solid-js";
3
- import { Button, Field, Icon, IconButton } from "@devslab/dds-solid";
1
+ import { createComponent, escape, memo, mergeProps, ssr, ssrAttribute, ssrElement, ssrHydrationKey } from "solid-js/web";
2
+ import { For, Show, createMemo, createSignal, createUniqueId, onCleanup, onMount } from "solid-js";
3
+ import { Button, Dialog, Field, Icon, IconButton, Switch } from "@devslab/dds-solid";
4
4
  //#region src/core/locales.mjs
5
5
  var LOCALES = Object.freeze([
6
6
  {
@@ -350,31 +350,31 @@ var FLAGS_BY_COUNTRY = Object.freeze({
350
350
  var flagBodiesNow = () => FLAGS_BY_COUNTRY;
351
351
  //#endregion
352
352
  //#region src/solid/locale-menu.tsx
353
- var _tmpl$$5 = [
353
+ var _tmpl$$6 = [
354
354
  "<svg",
355
355
  " class=\"site-flag-sprite\" aria-hidden=\"true\">",
356
356
  "</svg>"
357
357
  ];
358
- var _tmpl$2$3 = ["<svg", " class=\"site-flag-sprite\" aria-hidden=\"true\"></svg>"];
359
- var _tmpl$3$3 = [
358
+ var _tmpl$2$4 = ["<svg", " class=\"site-flag-sprite\" aria-hidden=\"true\"></svg>"];
359
+ var _tmpl$3$4 = [
360
360
  "<svg",
361
361
  " aria-hidden=\"true\"><use href=\"",
362
362
  "\"></use></svg>"
363
363
  ];
364
- var _tmpl$4$3 = [
364
+ var _tmpl$4$4 = [
365
365
  "<label",
366
366
  "><span class=\"dds-sr-only\">",
367
367
  "</span><span class=\"dds-select site-locale\"><select class=\"dds-select__input\"",
368
368
  ">",
369
369
  "</select></span></label>"
370
370
  ];
371
- var _tmpl$5$3 = [
371
+ var _tmpl$5$4 = [
372
372
  "<option",
373
373
  "",
374
374
  ">",
375
375
  "</option>"
376
376
  ];
377
- var _tmpl$6$3 = [
377
+ var _tmpl$6$4 = [
378
378
  "<details",
379
379
  " class=\"site-locale-flag\"><summary class=\"site-locale-flag__trigger\"",
380
380
  "><!--$-->",
@@ -429,20 +429,20 @@ function spriteMarkup(countries, bodies, uid) {
429
429
  */
430
430
  function FlagSprite(props) {
431
431
  const bodies = flagBodiesNow();
432
- if (bodies) return ssr(_tmpl$$5, ssrHydrationKey(), spriteMarkup(props.countries, bodies, props.uid));
433
- return ssr(_tmpl$2$3, ssrHydrationKey());
432
+ if (bodies) return ssr(_tmpl$$6, ssrHydrationKey(), spriteMarkup(props.countries, bodies, props.uid));
433
+ return ssr(_tmpl$2$4, ssrHydrationKey());
434
434
  }
435
435
  function Flag(props) {
436
436
  const country = () => flagCountryFor(props.locale, props.registry);
437
- return ssr(_tmpl$3$3, ssrHydrationKey() + ssrAttribute("class", escape(props.class, true), false) + ssrAttribute("viewBox", escape(FLAG_VIEWBOX, true), false), `#${escape(symbolId(country(), props.uid), true)}`);
437
+ return ssr(_tmpl$3$4, ssrHydrationKey() + ssrAttribute("class", escape(props.class, true), false) + ssrAttribute("viewBox", escape(FLAG_VIEWBOX, true), false), `#${escape(symbolId(country(), props.uid), true)}`);
438
438
  }
439
439
  function SelectLocaleMenu(props) {
440
440
  const registry = () => registryOf(props);
441
- return ssr(_tmpl$4$3, ssrHydrationKey(), escape(props.messages.localeLabel), ssrAttribute("aria-label", escape(props.messages.localeLabel, true), false), escape(createComponent(For, {
441
+ return ssr(_tmpl$4$4, ssrHydrationKey(), escape(props.messages.localeLabel), ssrAttribute("aria-label", escape(props.messages.localeLabel, true), false), escape(createComponent(For, {
442
442
  get each() {
443
443
  return registry().LOCALES;
444
444
  },
445
- children: (locale) => ssr(_tmpl$5$3, ssrHydrationKey() + ssrAttribute("value", escape(locale.code, true), false) + ssrAttribute("lang", escape(locale.code, true), false) + ssrAttribute("dir", escape(locale.dir, true), false), ssrAttribute("selected", locale.code === props.state.locale, true), escape(locale.nativeName))
445
+ children: (locale) => ssr(_tmpl$5$4, ssrHydrationKey() + ssrAttribute("value", escape(locale.code, true), false) + ssrAttribute("lang", escape(locale.code, true), false) + ssrAttribute("dir", escape(locale.dir, true), false), ssrAttribute("selected", locale.code === props.state.locale, true), escape(locale.nativeName))
446
446
  })));
447
447
  }
448
448
  function FlagLocaleMenu(props) {
@@ -454,7 +454,7 @@ function FlagLocaleMenu(props) {
454
454
  const name = current()?.nativeName;
455
455
  return name ? `${props.messages.localeLabel}: ${name}` : props.messages.localeLabel;
456
456
  };
457
- return ssr(_tmpl$6$3, ssrHydrationKey(), ssrAttribute("aria-label", escape(triggerLabel(), true), false) + ssrAttribute("title", escape(props.messages.localeLabel, true), false), escape(createComponent(FlagSprite, {
457
+ return ssr(_tmpl$6$4, ssrHydrationKey(), ssrAttribute("aria-label", escape(triggerLabel(), true), false) + ssrAttribute("title", escape(props.messages.localeLabel, true), false), escape(createComponent(FlagSprite, {
458
458
  get countries() {
459
459
  return countries();
460
460
  },
@@ -488,6 +488,245 @@ function LocaleMenu(props) {
488
488
  return props.variant === "flag" ? createComponent(FlagLocaleMenu, props) : createComponent(SelectLocaleMenu, props);
489
489
  }
490
490
  //#endregion
491
+ //#region src/solid/consent.tsx
492
+ var _tmpl$$5 = [
493
+ "<section",
494
+ " class=\"site-consent\"",
495
+ "><div class=\"site-consent__inner\"><div class=\"site-consent__copy\"><h2 class=\"site-consent__title\">",
496
+ "</h2><p class=\"site-consent__body\"><!--$-->",
497
+ "<!--/--> <a class=\"site-consent__link\"",
498
+ ">",
499
+ "</a></p></div><div class=\"site-consent__actions\"><!--$-->",
500
+ "<!--/--><!--$-->",
501
+ "<!--/--><!--$-->",
502
+ "<!--/--></div><!--$-->",
503
+ "<!--/--></div></section>"
504
+ ];
505
+ var _tmpl$2$3 = [
506
+ "<ul",
507
+ " class=\"site-consent-categories\" role=\"list\"><li class=\"site-consent-category\"><div class=\"site-consent-category__copy\"><h3 class=\"site-consent-category__title\">",
508
+ "</h3><p class=\"site-consent-category__body\">",
509
+ "</p></div><span class=\"dds-badge site-consent-category__status\">",
510
+ "</span></li><li class=\"site-consent-category\"><div class=\"site-consent-category__copy\"><h3 class=\"site-consent-category__title\">",
511
+ "</h3><p id=\"site-consent-analytics-body\" class=\"site-consent-category__body\">",
512
+ "</p></div><!--$-->",
513
+ "<!--/--></li></ul>"
514
+ ];
515
+ var _tmpl$3$3 = [
516
+ "<p",
517
+ " class=\"site-consent-dialog__policy\"><a class=\"site-consent__link\"",
518
+ ">",
519
+ "</a></p>"
520
+ ];
521
+ var _tmpl$4$3 = [
522
+ "<p",
523
+ " class=\"dds-sr-only\" role=\"status\">",
524
+ "</p>"
525
+ ];
526
+ var _tmpl$5$3 = [
527
+ "<span",
528
+ " class=\"dds-sr-only\">",
529
+ "</span>"
530
+ ];
531
+ var _tmpl$6$3 = [
532
+ "<button",
533
+ " type=\"button\"",
534
+ " aria-haspopup=\"dialog\">",
535
+ "</button>"
536
+ ];
537
+ /**
538
+ * The consent bar and its settings dialog (D-034).
539
+ *
540
+ * Renders nothing on the server and nothing during hydration: the bar comes
541
+ * in after mount, when the browser's own cookie is known. So it can never
542
+ * disagree with the server's markup, and a page without JavaScript shows no
543
+ * bar and loads no analytics.
544
+ *
545
+ * The bar's three choices are the same button, the same size: "모두 허용",
546
+ * "거부", "설정". Closing it any other way (✕, Escape) is no decision —
547
+ * nothing loads, and the next visit asks again.
548
+ */
549
+ function ConsentBanner(props) {
550
+ const [mounted, setMounted] = createSignal(false);
551
+ const [undecided, setUndecided] = createSignal(false);
552
+ const [dismissed, setDismissed] = createSignal(false);
553
+ const [settingsOpen, setSettingsOpen] = createSignal(false);
554
+ const [analytics, setAnalytics] = createSignal(false);
555
+ const [announcement, setAnnouncement] = createSignal("");
556
+ const sync = () => {
557
+ setUndecided(props.controller.needsDecision());
558
+ setDismissed(props.controller.dismissed());
559
+ };
560
+ const openSettings = () => {
561
+ setAnalytics(props.controller.analyticsGranted());
562
+ setSettingsOpen(true);
563
+ };
564
+ onMount(() => {
565
+ const controller = props.controller;
566
+ controller.start();
567
+ sync();
568
+ onCleanup(controller.subscribe((event) => {
569
+ if (event.type === "open-settings") openSettings();
570
+ else sync();
571
+ }));
572
+ setMounted(true);
573
+ });
574
+ const keepFocus = () => setTimeout(() => {
575
+ if (document.activeElement && document.activeElement !== document.body) return;
576
+ document.getElementById("main-content")?.focus({ preventScroll: true });
577
+ }, 0);
578
+ const decide = (choice) => {
579
+ choice();
580
+ setSettingsOpen(false);
581
+ setAnnouncement("");
582
+ queueMicrotask(() => setAnnouncement(props.messages.saved));
583
+ keepFocus();
584
+ };
585
+ const acceptAll = () => decide(() => props.controller.acceptAll());
586
+ const rejectAll = () => decide(() => props.controller.rejectAll());
587
+ const dismiss = () => {
588
+ props.controller.dismiss();
589
+ keepFocus();
590
+ };
591
+ return createComponent(Show, {
592
+ get when() {
593
+ return mounted();
594
+ },
595
+ get children() {
596
+ return [
597
+ createComponent(Show, {
598
+ get when() {
599
+ return memo(() => !!undecided())() && !dismissed();
600
+ },
601
+ get children() {
602
+ return ssr(_tmpl$$5, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.regionLabel, true), false), escape(props.messages.title), escape(props.messages.body), ssrAttribute("href", escape(props.privacyHref, true), false), escape(props.messages.privacyLink), escape(createComponent(Button, {
603
+ "class": "site-consent__action",
604
+ tone: "secondary",
605
+ onClick: acceptAll,
606
+ get children() {
607
+ return props.messages.acceptAll;
608
+ }
609
+ })), escape(createComponent(Button, {
610
+ "class": "site-consent__action",
611
+ tone: "secondary",
612
+ onClick: rejectAll,
613
+ get children() {
614
+ return props.messages.rejectAll;
615
+ }
616
+ })), escape(createComponent(Button, {
617
+ "class": "site-consent__action",
618
+ tone: "secondary",
619
+ "aria-haspopup": "dialog",
620
+ onClick: openSettings,
621
+ get children() {
622
+ return props.messages.settings;
623
+ }
624
+ })), escape(createComponent(IconButton, {
625
+ "class": "site-consent__dismiss",
626
+ get ["aria-label"]() {
627
+ return props.messages.dismiss;
628
+ },
629
+ get title() {
630
+ return props.messages.dismiss;
631
+ },
632
+ onClick: dismiss,
633
+ get children() {
634
+ return createComponent(Icon, {
635
+ name: "close",
636
+ size: 20
637
+ });
638
+ }
639
+ })));
640
+ }
641
+ }),
642
+ createComponent(Dialog, {
643
+ id: "site-consent-settings",
644
+ "class": "site-consent-dialog",
645
+ get open() {
646
+ return settingsOpen();
647
+ },
648
+ onOpenChange: setSettingsOpen,
649
+ get title() {
650
+ return props.messages.settingsTitle;
651
+ },
652
+ get description() {
653
+ return props.messages.settingsIntro;
654
+ },
655
+ get actions() {
656
+ return [
657
+ createComponent(Button, {
658
+ "class": "site-consent__action",
659
+ tone: "secondary",
660
+ onClick: acceptAll,
661
+ get children() {
662
+ return props.messages.acceptAll;
663
+ }
664
+ }),
665
+ createComponent(Button, {
666
+ "class": "site-consent__action",
667
+ tone: "secondary",
668
+ onClick: rejectAll,
669
+ get children() {
670
+ return props.messages.rejectAll;
671
+ }
672
+ }),
673
+ createComponent(Button, {
674
+ "class": "site-consent__action",
675
+ tone: "secondary",
676
+ onClick: () => decide(() => props.controller.save({ analytics: analytics() })),
677
+ get children() {
678
+ return props.messages.save;
679
+ }
680
+ })
681
+ ];
682
+ },
683
+ get children() {
684
+ return [
685
+ createComponent(IconButton, {
686
+ "class": "site-consent-dialog__close",
687
+ get ["aria-label"]() {
688
+ return props.messages.close;
689
+ },
690
+ get title() {
691
+ return props.messages.close;
692
+ },
693
+ onClick: () => setSettingsOpen(false),
694
+ get children() {
695
+ return createComponent(Icon, {
696
+ name: "close",
697
+ size: 20
698
+ });
699
+ }
700
+ }),
701
+ ssr(_tmpl$2$3, ssrHydrationKey(), escape(props.messages.necessaryTitle), escape(props.messages.necessaryBody), escape(props.messages.necessaryStatus), escape(props.messages.analyticsTitle), escape(props.messages.analyticsBody), escape(createComponent(Switch, {
702
+ "class": "site-consent-category__switch",
703
+ get checked() {
704
+ return analytics();
705
+ },
706
+ onCheckedChange: setAnalytics,
707
+ "aria-describedby": "site-consent-analytics-body",
708
+ get label() {
709
+ return ssr(_tmpl$5$3, ssrHydrationKey(), escape(props.messages.analyticsSwitch));
710
+ }
711
+ }))),
712
+ ssr(_tmpl$3$3, ssrHydrationKey(), ssrAttribute("href", escape(props.privacyHref, true), false), escape(props.messages.privacyLink))
713
+ ];
714
+ }
715
+ }),
716
+ ssr(_tmpl$4$3, ssrHydrationKey(), escape(announcement()))
717
+ ];
718
+ }
719
+ });
720
+ }
721
+ /**
722
+ * Re-opens the settings dialog from anywhere — the footer's "쿠키 설정", an
723
+ * account page. The ConsentBanner mounted on the page listens for it; a page
724
+ * without one has nothing to open.
725
+ */
726
+ function ConsentSettingsButton(props) {
727
+ return ssr(_tmpl$6$3, ssrHydrationKey(), ssrAttribute("class", props.class ? `site-consent-trigger ${escape(props.class, true)}` : "site-consent-trigger", false), escape(props.children));
728
+ }
729
+ //#endregion
491
730
  //#region src/solid/chrome.tsx
492
731
  var _tmpl$$4 = [
493
732
  "<header",
@@ -540,20 +779,26 @@ var _tmpl$7$2 = [
540
779
  var _tmpl$8$1 = [
541
780
  "<ul",
542
781
  " class=\"site-footer__links\"><!--$-->",
782
+ "<!--/--><!--$-->",
543
783
  "<!--/--><li>",
544
784
  "</li></ul>"
545
785
  ];
546
786
  var _tmpl$9$1 = [
787
+ "<li",
788
+ ">",
789
+ "</li>"
790
+ ];
791
+ var _tmpl$0$1 = [
547
792
  "<bdi",
548
793
  ">",
549
794
  "</bdi>"
550
795
  ];
551
- var _tmpl$0$1 = [
796
+ var _tmpl$1$1 = [
552
797
  "<a",
553
798
  "><bdi>",
554
799
  "</bdi></a>"
555
800
  ];
556
- var _tmpl$1$1 = [
801
+ var _tmpl$10 = [
557
802
  "<footer",
558
803
  " class=\"site-footer\"",
559
804
  "><div class=\"site-footer__inner\"><!--$-->",
@@ -561,13 +806,13 @@ var _tmpl$1$1 = [
561
806
  "<!--/--><!--$-->",
562
807
  "<!--/--></div></div></footer>"
563
808
  ];
564
- var _tmpl$10 = [
809
+ var _tmpl$11 = [
565
810
  "<div",
566
811
  " class=\"site-footer__identity\"><!--$-->",
567
812
  "<!--/--><div class=\"site-footer__details\">",
568
813
  "</div></div>"
569
814
  ];
570
- var _tmpl$11 = [
815
+ var _tmpl$12 = [
571
816
  "<nav",
572
817
  " class=\"site-footer__nav\"",
573
818
  ">",
@@ -718,16 +963,28 @@ function SiteFooter(props) {
718
963
  return props.links;
719
964
  },
720
965
  children: (item) => ssr(_tmpl$2$2, ssrHydrationKey(), ssrAttribute("class", escape(linkClass(item), true), false) + ssrAttribute("href", escape(item.href, true), false), escape(item.label))
966
+ })), escape(createComponent(Show, {
967
+ get when() {
968
+ return props.consentSettings;
969
+ },
970
+ children: (settings) => ssr(_tmpl$9$1, ssrHydrationKey(), escape(createComponent(ConsentSettingsButton, {
971
+ get controller() {
972
+ return settings().controller;
973
+ },
974
+ get children() {
975
+ return settings().label;
976
+ }
977
+ })))
721
978
  })), escape(createComponent(Show, {
722
979
  get when() {
723
980
  return props.copyrightHref;
724
981
  },
725
982
  get fallback() {
726
- return ssr(_tmpl$9$1, ssrHydrationKey(), escape(props.copyright));
983
+ return ssr(_tmpl$0$1, ssrHydrationKey(), escape(props.copyright));
727
984
  },
728
- children: (href) => ssr(_tmpl$0$1, ssrHydrationKey() + ssrAttribute("href", escape(href(), true), false), escape(props.copyright))
985
+ children: (href) => ssr(_tmpl$1$1, ssrHydrationKey() + ssrAttribute("href", escape(href(), true), false), escape(props.copyright))
729
986
  })));
730
- return ssr(_tmpl$1$1, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.footerLabel, true), false), escape(createComponent(Show, {
987
+ return ssr(_tmpl$10, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.footerLabel, true), false), escape(createComponent(Show, {
731
988
  get when() {
732
989
  return props.locale;
733
990
  },
@@ -752,7 +1009,7 @@ function SiteFooter(props) {
752
1009
  get fallback() {
753
1010
  return brandLine();
754
1011
  },
755
- children: (content) => ssr(_tmpl$10, ssrHydrationKey(), escape(brandLine()), escape(content()))
1012
+ children: (content) => ssr(_tmpl$11, ssrHydrationKey(), escape(brandLine()), escape(content()))
756
1013
  })), escape(createComponent(Show, {
757
1014
  get when() {
758
1015
  return props.linksLabel;
@@ -760,7 +1017,7 @@ function SiteFooter(props) {
760
1017
  get fallback() {
761
1018
  return linkList();
762
1019
  },
763
- children: (label) => ssr(_tmpl$11, ssrHydrationKey(), ssrAttribute("aria-label", escape(label(), true), false), escape(linkList()))
1020
+ children: (label) => ssr(_tmpl$12, ssrHydrationKey(), ssrAttribute("aria-label", escape(label(), true), false), escape(linkList()))
764
1021
  })));
765
1022
  }
766
1023
  //#endregion
@@ -1061,6 +1318,6 @@ function PricingNote(props) {
1061
1318
  return ssr(_tmpl$1, ssrHydrationKey(), escape(props.children), escape(props.action));
1062
1319
  }
1063
1320
  //#endregion
1064
- export { ErrorLayout, FeatureRows, HeroSplit, LegalLayout, LocaleMenu, MarketingShell, NotFoundLayout, OssProductMark, PricingNote, RequestAccessForm, SectionBlock, SectionHead, SiteFooter, SiteHeader, StatusBanner, StepFlow, ThemeToggle };
1321
+ export { ConsentBanner, ConsentSettingsButton, ErrorLayout, FeatureRows, HeroSplit, LegalLayout, LocaleMenu, MarketingShell, NotFoundLayout, OssProductMark, PricingNote, RequestAccessForm, SectionBlock, SectionHead, SiteFooter, SiteHeader, StatusBanner, StepFlow, ThemeToggle };
1065
1322
 
1066
1323
  //# sourceMappingURL=solid.server.js.map