@devslab/site-kit 0.15.0 → 0.17.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,238 @@ 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
+ /** A link with a non-empty `#fragment`: the policy section, not the top of the page. */
538
+ var POLICY_SECTION_HREF = /^[^#\s]*#[^#\s]+$/;
539
+ /**
540
+ * The consent bar and its settings dialog (D-034).
541
+ *
542
+ * Renders nothing on the server and nothing during hydration: the bar comes
543
+ * in after mount, when the browser's own cookie is known. So it can never
544
+ * disagree with the server's markup, and a page without JavaScript shows no
545
+ * bar and loads no analytics.
546
+ *
547
+ * The bar's three choices are the same button, the same size: "모두 허용",
548
+ * "거부", "설정". Closing it any other way (✕, Escape) is no decision —
549
+ * nothing loads, and the next visit asks again. Its text is short; the
550
+ * disclosure lives in the policy section `learnMoreHref` points at.
551
+ */
552
+ function ConsentBanner(props) {
553
+ if (typeof props.learnMoreHref !== "string" || !POLICY_SECTION_HREF.test(props.learnMoreHref)) throw new RangeError(`ConsentBanner: learnMoreHref must link to the privacy policy's analytics section with its #anchor (e.g. /privacy#analytics), got ${JSON.stringify(props.learnMoreHref)}`);
554
+ const [mounted, setMounted] = createSignal(false);
555
+ const [undecided, setUndecided] = createSignal(false);
556
+ const [dismissed, setDismissed] = createSignal(false);
557
+ const [settingsOpen, setSettingsOpen] = createSignal(false);
558
+ const [analytics, setAnalytics] = createSignal(false);
559
+ const [announcement, setAnnouncement] = createSignal("");
560
+ const sync = () => {
561
+ setUndecided(props.controller.needsDecision());
562
+ setDismissed(props.controller.dismissed());
563
+ };
564
+ const openSettings = () => {
565
+ setAnalytics(props.controller.analyticsGranted());
566
+ setSettingsOpen(true);
567
+ };
568
+ onMount(() => {
569
+ const controller = props.controller;
570
+ controller.start();
571
+ sync();
572
+ onCleanup(controller.subscribe((event) => {
573
+ if (event.type === "open-settings") openSettings();
574
+ else sync();
575
+ }));
576
+ setMounted(true);
577
+ });
578
+ const keepFocus = () => setTimeout(() => {
579
+ if (document.activeElement && document.activeElement !== document.body) return;
580
+ document.getElementById("main-content")?.focus({ preventScroll: true });
581
+ }, 0);
582
+ const decide = (choice) => {
583
+ choice();
584
+ setSettingsOpen(false);
585
+ setAnnouncement("");
586
+ queueMicrotask(() => setAnnouncement(props.messages.saved));
587
+ keepFocus();
588
+ };
589
+ const acceptAll = () => decide(() => props.controller.acceptAll());
590
+ const rejectAll = () => decide(() => props.controller.rejectAll());
591
+ const dismiss = () => {
592
+ props.controller.dismiss();
593
+ keepFocus();
594
+ };
595
+ return createComponent(Show, {
596
+ get when() {
597
+ return mounted();
598
+ },
599
+ get children() {
600
+ return [
601
+ createComponent(Show, {
602
+ get when() {
603
+ return memo(() => !!undecided())() && !dismissed();
604
+ },
605
+ get children() {
606
+ 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.learnMoreHref, true), false), escape(props.messages.learnMore), escape(createComponent(Button, {
607
+ "class": "site-consent__action",
608
+ tone: "secondary",
609
+ onClick: acceptAll,
610
+ get children() {
611
+ return props.messages.acceptAll;
612
+ }
613
+ })), escape(createComponent(Button, {
614
+ "class": "site-consent__action",
615
+ tone: "secondary",
616
+ onClick: rejectAll,
617
+ get children() {
618
+ return props.messages.rejectAll;
619
+ }
620
+ })), escape(createComponent(Button, {
621
+ "class": "site-consent__action",
622
+ tone: "secondary",
623
+ "aria-haspopup": "dialog",
624
+ onClick: openSettings,
625
+ get children() {
626
+ return props.messages.settings;
627
+ }
628
+ })), escape(createComponent(IconButton, {
629
+ "class": "site-consent__dismiss",
630
+ get ["aria-label"]() {
631
+ return props.messages.dismiss;
632
+ },
633
+ get title() {
634
+ return props.messages.dismiss;
635
+ },
636
+ onClick: dismiss,
637
+ get children() {
638
+ return createComponent(Icon, {
639
+ name: "close",
640
+ size: 20
641
+ });
642
+ }
643
+ })));
644
+ }
645
+ }),
646
+ createComponent(Dialog, {
647
+ id: "site-consent-settings",
648
+ "class": "site-consent-dialog",
649
+ get open() {
650
+ return settingsOpen();
651
+ },
652
+ onOpenChange: setSettingsOpen,
653
+ get title() {
654
+ return props.messages.settingsTitle;
655
+ },
656
+ get description() {
657
+ return props.messages.settingsIntro;
658
+ },
659
+ get actions() {
660
+ return [createComponent(Button, {
661
+ "class": "site-consent__action",
662
+ tone: "secondary",
663
+ onClick: () => setSettingsOpen(false),
664
+ get children() {
665
+ return props.messages.cancel;
666
+ }
667
+ }), createComponent(Button, {
668
+ "class": "site-consent__action",
669
+ tone: "secondary",
670
+ onClick: () => decide(() => props.controller.save({ analytics: analytics() })),
671
+ get children() {
672
+ return props.messages.save;
673
+ }
674
+ })];
675
+ },
676
+ get children() {
677
+ return [
678
+ createComponent(IconButton, {
679
+ "class": "site-consent-dialog__close",
680
+ get ["aria-label"]() {
681
+ return props.messages.close;
682
+ },
683
+ get title() {
684
+ return props.messages.close;
685
+ },
686
+ onClick: () => setSettingsOpen(false),
687
+ get children() {
688
+ return createComponent(Icon, {
689
+ name: "close",
690
+ size: 20
691
+ });
692
+ }
693
+ }),
694
+ 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, {
695
+ "class": "site-consent-category__switch",
696
+ get checked() {
697
+ return analytics();
698
+ },
699
+ onCheckedChange: setAnalytics,
700
+ "aria-describedby": "site-consent-analytics-body",
701
+ get label() {
702
+ return ssr(_tmpl$5$3, ssrHydrationKey(), escape(props.messages.analyticsSwitch));
703
+ }
704
+ }))),
705
+ ssr(_tmpl$3$3, ssrHydrationKey(), ssrAttribute("href", escape(props.privacyHref, true), false), escape(props.messages.privacyLink))
706
+ ];
707
+ }
708
+ }),
709
+ ssr(_tmpl$4$3, ssrHydrationKey(), escape(announcement()))
710
+ ];
711
+ }
712
+ });
713
+ }
714
+ /**
715
+ * Re-opens the settings dialog from anywhere — the footer's "쿠키 설정", an
716
+ * account page. The ConsentBanner mounted on the page listens for it; a page
717
+ * without one has nothing to open.
718
+ */
719
+ function ConsentSettingsButton(props) {
720
+ return ssr(_tmpl$6$3, ssrHydrationKey(), ssrAttribute("class", props.class ? `site-consent-trigger ${escape(props.class, true)}` : "site-consent-trigger", false), escape(props.children));
721
+ }
722
+ //#endregion
491
723
  //#region src/solid/chrome.tsx
492
724
  var _tmpl$$4 = [
493
725
  "<header",
@@ -540,20 +772,26 @@ var _tmpl$7$2 = [
540
772
  var _tmpl$8$1 = [
541
773
  "<ul",
542
774
  " class=\"site-footer__links\"><!--$-->",
775
+ "<!--/--><!--$-->",
543
776
  "<!--/--><li>",
544
777
  "</li></ul>"
545
778
  ];
546
779
  var _tmpl$9$1 = [
780
+ "<li",
781
+ ">",
782
+ "</li>"
783
+ ];
784
+ var _tmpl$0$1 = [
547
785
  "<bdi",
548
786
  ">",
549
787
  "</bdi>"
550
788
  ];
551
- var _tmpl$0$1 = [
789
+ var _tmpl$1$1 = [
552
790
  "<a",
553
791
  "><bdi>",
554
792
  "</bdi></a>"
555
793
  ];
556
- var _tmpl$1$1 = [
794
+ var _tmpl$10 = [
557
795
  "<footer",
558
796
  " class=\"site-footer\"",
559
797
  "><div class=\"site-footer__inner\"><!--$-->",
@@ -561,13 +799,13 @@ var _tmpl$1$1 = [
561
799
  "<!--/--><!--$-->",
562
800
  "<!--/--></div></div></footer>"
563
801
  ];
564
- var _tmpl$10 = [
802
+ var _tmpl$11 = [
565
803
  "<div",
566
804
  " class=\"site-footer__identity\"><!--$-->",
567
805
  "<!--/--><div class=\"site-footer__details\">",
568
806
  "</div></div>"
569
807
  ];
570
- var _tmpl$11 = [
808
+ var _tmpl$12 = [
571
809
  "<nav",
572
810
  " class=\"site-footer__nav\"",
573
811
  ">",
@@ -718,16 +956,28 @@ function SiteFooter(props) {
718
956
  return props.links;
719
957
  },
720
958
  children: (item) => ssr(_tmpl$2$2, ssrHydrationKey(), ssrAttribute("class", escape(linkClass(item), true), false) + ssrAttribute("href", escape(item.href, true), false), escape(item.label))
959
+ })), escape(createComponent(Show, {
960
+ get when() {
961
+ return props.consentSettings;
962
+ },
963
+ children: (settings) => ssr(_tmpl$9$1, ssrHydrationKey(), escape(createComponent(ConsentSettingsButton, {
964
+ get controller() {
965
+ return settings().controller;
966
+ },
967
+ get children() {
968
+ return settings().label;
969
+ }
970
+ })))
721
971
  })), escape(createComponent(Show, {
722
972
  get when() {
723
973
  return props.copyrightHref;
724
974
  },
725
975
  get fallback() {
726
- return ssr(_tmpl$9$1, ssrHydrationKey(), escape(props.copyright));
976
+ return ssr(_tmpl$0$1, ssrHydrationKey(), escape(props.copyright));
727
977
  },
728
- children: (href) => ssr(_tmpl$0$1, ssrHydrationKey() + ssrAttribute("href", escape(href(), true), false), escape(props.copyright))
978
+ children: (href) => ssr(_tmpl$1$1, ssrHydrationKey() + ssrAttribute("href", escape(href(), true), false), escape(props.copyright))
729
979
  })));
730
- return ssr(_tmpl$1$1, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.footerLabel, true), false), escape(createComponent(Show, {
980
+ return ssr(_tmpl$10, ssrHydrationKey(), ssrAttribute("aria-label", escape(props.messages.footerLabel, true), false), escape(createComponent(Show, {
731
981
  get when() {
732
982
  return props.locale;
733
983
  },
@@ -752,7 +1002,7 @@ function SiteFooter(props) {
752
1002
  get fallback() {
753
1003
  return brandLine();
754
1004
  },
755
- children: (content) => ssr(_tmpl$10, ssrHydrationKey(), escape(brandLine()), escape(content()))
1005
+ children: (content) => ssr(_tmpl$11, ssrHydrationKey(), escape(brandLine()), escape(content()))
756
1006
  })), escape(createComponent(Show, {
757
1007
  get when() {
758
1008
  return props.linksLabel;
@@ -760,7 +1010,7 @@ function SiteFooter(props) {
760
1010
  get fallback() {
761
1011
  return linkList();
762
1012
  },
763
- children: (label) => ssr(_tmpl$11, ssrHydrationKey(), ssrAttribute("aria-label", escape(label(), true), false), escape(linkList()))
1013
+ children: (label) => ssr(_tmpl$12, ssrHydrationKey(), ssrAttribute("aria-label", escape(label(), true), false), escape(linkList()))
764
1014
  })));
765
1015
  }
766
1016
  //#endregion
@@ -1061,6 +1311,6 @@ function PricingNote(props) {
1061
1311
  return ssr(_tmpl$1, ssrHydrationKey(), escape(props.children), escape(props.action));
1062
1312
  }
1063
1313
  //#endregion
1064
- export { ErrorLayout, FeatureRows, HeroSplit, LegalLayout, LocaleMenu, MarketingShell, NotFoundLayout, OssProductMark, PricingNote, RequestAccessForm, SectionBlock, SectionHead, SiteFooter, SiteHeader, StatusBanner, StepFlow, ThemeToggle };
1314
+ export { ConsentBanner, ConsentSettingsButton, ErrorLayout, FeatureRows, HeroSplit, LegalLayout, LocaleMenu, MarketingShell, NotFoundLayout, OssProductMark, PricingNote, RequestAccessForm, SectionBlock, SectionHead, SiteFooter, SiteHeader, StatusBanner, StepFlow, ThemeToggle };
1065
1315
 
1066
1316
  //# sourceMappingURL=solid.server.js.map