@natachah/vanilla-frontend 0.0.2

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.
Files changed (104) hide show
  1. package/.gitlab-ci.yml +40 -0
  2. package/LICENSE.md +7 -0
  3. package/README.md +11 -0
  4. package/docs/index.html +36 -0
  5. package/docs/main.js +32 -0
  6. package/docs/pages/components/badge.html +154 -0
  7. package/docs/pages/components/button.html +186 -0
  8. package/docs/pages/components/card.html +184 -0
  9. package/docs/pages/components/dialog.html +334 -0
  10. package/docs/pages/components/disclosure.html +310 -0
  11. package/docs/pages/components/dropdown.html +255 -0
  12. package/docs/pages/components/form.html +331 -0
  13. package/docs/pages/components/list.html +140 -0
  14. package/docs/pages/components/loading.html +58 -0
  15. package/docs/pages/components/media.html +130 -0
  16. package/docs/pages/components/nav.html +119 -0
  17. package/docs/pages/components/progress.html +47 -0
  18. package/docs/pages/components/slider.html +311 -0
  19. package/docs/pages/components/table.html +168 -0
  20. package/docs/pages/javascript/autofill.html +170 -0
  21. package/docs/pages/javascript/checkall.html +59 -0
  22. package/docs/pages/javascript/comfort.html +134 -0
  23. package/docs/pages/javascript/consent.html +112 -0
  24. package/docs/pages/javascript/cookie.html +81 -0
  25. package/docs/pages/javascript/form.html +199 -0
  26. package/docs/pages/javascript/scroll.html +209 -0
  27. package/docs/pages/javascript/sidebar.html +53 -0
  28. package/docs/pages/javascript/sortable.html +148 -0
  29. package/docs/pages/javascript/toggle.html +191 -0
  30. package/docs/pages/javascript/tree.html +221 -0
  31. package/docs/pages/layout/grid.html +201 -0
  32. package/docs/pages/layout/reset.html +53 -0
  33. package/docs/pages/layout/typography.html +324 -0
  34. package/docs/pages/quick-start/conventions.html +112 -0
  35. package/docs/pages/quick-start/customization.html +187 -0
  36. package/docs/pages/quick-start/installation.html +95 -0
  37. package/docs/pages/quick-start/mixins.html +228 -0
  38. package/docs/pages/test.html +15 -0
  39. package/docs/src/js/demo.js +98 -0
  40. package/docs/src/js/doc-code.js +102 -0
  41. package/docs/src/js/doc-demo.js +14 -0
  42. package/docs/src/js/doc-layout.js +108 -0
  43. package/docs/src/scss/demo.scss +77 -0
  44. package/docs/src/scss/layout.scss +160 -0
  45. package/docs/src/scss/style.scss +278 -0
  46. package/docs/vite.config.mjs +23 -0
  47. package/esbuild.mjs +25 -0
  48. package/js/_autofill.js +131 -0
  49. package/js/_check-all.js +77 -0
  50. package/js/_comfort.js +174 -0
  51. package/js/_consent.js +84 -0
  52. package/js/_dialog.js +164 -0
  53. package/js/_dropdown.js +101 -0
  54. package/js/_scroll.js +184 -0
  55. package/js/_sidebar.js +97 -0
  56. package/js/_slider.js +249 -0
  57. package/js/_sortable.js +143 -0
  58. package/js/_tabpanel.js +88 -0
  59. package/js/_toggle.js +123 -0
  60. package/js/_tree.js +85 -0
  61. package/js/tests/autofill.test.js +157 -0
  62. package/js/tests/base-component.test.js +108 -0
  63. package/js/tests/check-all.test.js +88 -0
  64. package/js/tests/comfort.test.js +219 -0
  65. package/js/tests/consent.test.js +84 -0
  66. package/js/tests/cookie.test.js +102 -0
  67. package/js/tests/dialog.test.js +189 -0
  68. package/js/tests/dropdown.test.js +115 -0
  69. package/js/tests/form-helper.test.js +155 -0
  70. package/js/tests/scroll.test.js +203 -0
  71. package/js/tests/sidebar.test.js +99 -0
  72. package/js/tests/slider.test.js +307 -0
  73. package/js/tests/sortable.test.js +124 -0
  74. package/js/tests/tabpanel.test.js +114 -0
  75. package/js/tests/toggle.test.js +190 -0
  76. package/js/tests/tree.test.js +165 -0
  77. package/js/utilities/_base-component.js +101 -0
  78. package/js/utilities/_cookie.js +98 -0
  79. package/js/utilities/_error.js +80 -0
  80. package/js/utilities/_form-helper.js +101 -0
  81. package/package.json +42 -0
  82. package/scss/_badge.scss +37 -0
  83. package/scss/_button.scss +34 -0
  84. package/scss/_card.scss +122 -0
  85. package/scss/_dialog.scss +116 -0
  86. package/scss/_disclosure.scss +101 -0
  87. package/scss/_dropdown.scss +68 -0
  88. package/scss/_form.scss +197 -0
  89. package/scss/_grid.scss +40 -0
  90. package/scss/_group.scss +57 -0
  91. package/scss/_list.scss +18 -0
  92. package/scss/_loading.scss +49 -0
  93. package/scss/_media.scss +37 -0
  94. package/scss/_nav.scss +72 -0
  95. package/scss/_progress.scss +40 -0
  96. package/scss/_slider.scss +35 -0
  97. package/scss/_table.scss +36 -0
  98. package/scss/utilities/_mixin.scss +322 -0
  99. package/scss/utilities/_reset.scss +145 -0
  100. package/scss/utilities/_typography.scss +107 -0
  101. package/scss/vanilla-frontend.scss +23 -0
  102. package/scss/variables/_root.scss +70 -0
  103. package/scss/variables/_setting.scss +63 -0
  104. package/vitest.config.js +7 -0
@@ -0,0 +1,95 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Documentations: Quick start > Installation</title>
8
+ </head>
9
+
10
+ <body data-preload>
11
+ <doc-layout>
12
+
13
+ <h1>Installation</h1>
14
+
15
+ <p>Install the package via <b>NPM</b></p>
16
+
17
+ <doc-code data-typ="sh">
18
+ npm i @natachah/vanilla-frontend
19
+ </doc-code>
20
+
21
+ <p>Then you can import the <b>SCSS</b> files:</p>
22
+
23
+ <doc-code data-type="scss">
24
+ @import '@natachah/vanilla-frontend/scss/vanilla-frontend.scss';
25
+ </doc-code>
26
+
27
+ <p>Or better, include only the files that you need, here the template with all files:</p>
28
+
29
+ <doc-code data-type="scss">
30
+ // Can be overide by your own variables files
31
+ @import '@natachah/vanilla-frontend/scss/variables/_root';
32
+ @import '@natachah/vanilla-frontend/scss/variables/_setting';
33
+
34
+ // Utilities
35
+ @import '@natachah/vanilla-frontend/scss/utilities/_mixin';
36
+ @import '@natachah/vanilla-frontend/scss/utilities/_reset';
37
+ @import '@natachah/vanilla-frontend/scss/utilities/_typography';
38
+
39
+ // Components
40
+ @import '@natachah/vanilla-frontend/scss/_badge';
41
+ @import '@natachah/vanilla-frontend/scss/_button';
42
+ @import '@natachah/vanilla-frontend/scss/_card';
43
+ @import '@natachah/vanilla-frontend/scss/_dialog';
44
+ @import '@natachah/vanilla-frontend/scss/_disclosure';
45
+ @import '@natachah/vanilla-frontend/scss/_dropdown';
46
+ @import '@natachah/vanilla-frontend/scss/_form';
47
+ @import '@natachah/vanilla-frontend/scss/_grid';
48
+ @import '@natachah/vanilla-frontend/scss/_group';
49
+ @import '@natachah/vanilla-frontend/scss/_list';
50
+ @import '@natachah/vanilla-frontend/scss/_loading';
51
+ @import '@natachah/vanilla-frontend/scss/_media';
52
+ @import '@natachah/vanilla-frontend/scss/_nav';
53
+ @import '@natachah/vanilla-frontend/scss/_progress';
54
+ @import '@natachah/vanilla-frontend/scss/_slider';
55
+ @import '@natachah/vanilla-frontend/scss/_table';
56
+ </doc-code>
57
+
58
+ <blockquote>
59
+ <p>There is no required files, but it's recommanded to have at least the reset and typography...</p>
60
+ </blockquote>
61
+
62
+ <p>Import the <b>Javascript</b> files that you need, here the template:</p>
63
+
64
+ <doc-code data-type="js">
65
+ // If you need to create some component, you can use this
66
+ import BaseComponent from "@natachah/vanilla-frontend/js/utilities/_base-component"
67
+ import ErrorMessage from "@natachah/vanilla-frontend/js/utilities/_error"
68
+ import Cookie from "@natachah/vanilla-frontend/js/utilities/_cookie"
69
+
70
+ // Here the helpers
71
+ import FormHelper from "@natachah/vanilla-frontend/js/utilities/_form-helper"
72
+
73
+ // Here the components
74
+ import Autofill from "@natachah/vanilla-frontend/js/_autofill"
75
+ import CheckAll from "@natachah/vanilla-frontend/js/_check-all"
76
+ import Comfort from "@natachah/vanilla-frontend/js/_comfort"
77
+ import Consent from "@natachah/vanilla-frontend/js/_consent"
78
+ import Dialog from "@natachah/vanilla-frontend/js/_dialog"
79
+ import Dropdown from "@natachah/vanilla-frontend/js/_dropdown"
80
+ import Scroll from "@natachah/vanilla-frontend/js/_scroll"
81
+ import Slider from "@natachah/vanilla-frontend/js/_slider"
82
+ import Sortable from "@natachah/vanilla-frontend/js/_sortable"
83
+ import Toggle from "@natachah/vanilla-frontend/js/_toggle"
84
+ import Tree from "@natachah/vanilla-frontend/js/_tree"
85
+ </doc-code>
86
+
87
+ <blockquote class="tip">
88
+ <p>Import only the files that you need to keep the assets lightweight !</p>
89
+ </blockquote>
90
+
91
+ </doc-layout>
92
+ <script type="module" src="/main.js"></script>
93
+ </body>
94
+
95
+ </html>
@@ -0,0 +1,228 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Documentations: Quick start > SCSS mixins</title>
8
+ </head>
9
+
10
+ <body data-preload>
11
+ <doc-layout>
12
+
13
+ <h1>SCSS Mixins</h1>
14
+
15
+ <p>The framework come with some helpfull SCSS mixins to re-use.</p>
16
+
17
+ <p>To use them, import this file:</p>
18
+
19
+ <doc-code data-type="scss">
20
+ @import '@natachah/vanilla-frontend/scss/utilities/_mixin';
21
+ </doc-code>
22
+
23
+ <h2>Create an item</h2>
24
+
25
+ <p>This mixin create an element as an item with some default style properties:</p>
26
+
27
+ <ul>
28
+ <li>Color</li>
29
+ <li>Background</li>
30
+ <li>Border</li>
31
+ <li>Border radius</li>
32
+ <li>Padding</li>
33
+ <li>...and more for each states</li>
34
+ </ul>
35
+
36
+ <doc-code data-type="scss">
37
+ /// Create a basic item that can be interactive or not
38
+ ///
39
+ /// @param {string} $name - Name of the component
40
+ /// @param {array} $states - List of interactions (can be: focus, hover, active, disabled)
41
+ /// @param {array} $properties - List of default properties (check in /variables/_setting.scss)
42
+ /// @access public
43
+ ///
44
+
45
+ @include as-item($name, $states: (), $properties: $default-item-properties)
46
+ </doc-code>
47
+
48
+ <p>This mixin also include the <b>outline</b> and <b>color</b> variations. It also create some CSS custom properties with the <code>$name</code> value as <code>--{$name}-color</code> with fallback values from the <code>$properties</code>.</p>
49
+
50
+ <blockquote class="warning">
51
+ <p>The default properties are set inside the <code>$default-item-properties</code> variable of the file <code>./scss/variables/_setting.scss</code></p>
52
+ </blockquote>
53
+
54
+ <h2>Create a list</h2>
55
+ <p>This mixin transform a <code>&lt;ul/ol/div&gt;</code> as a group list with all children as an item.</p>
56
+
57
+ <doc-code data-type="scss">
58
+ /// Create a basic list group that can be interactive
59
+ ///
60
+ /// @require {mixin} as-item
61
+ /// @param {string} $name - Name of the component
62
+ /// @param {array} $states - List of interactions (can be: focus, hover, active, disabled)
63
+ /// @param {array} $properties - List of default properties (check in /variables/_setting.scss)
64
+ /// @access public
65
+ ///
66
+
67
+ @include as-list($name, $states: (), $properties: $default-item-properties)
68
+ </doc-code>
69
+
70
+ <blockquote>
71
+ <p>This mixin is used for the <b>list</b> and <b>dropdown</b> components</p>
72
+ </blockquote>
73
+
74
+ <h2>Set outline variation</h2>
75
+
76
+ <p>This mixin will create the <code>.outline</code> class to transform an item to the outline varation.</p>
77
+
78
+ <div class="code-group">
79
+ <div role="tablist">
80
+ <button role="tab" aria-controls="scss">SCSS</button>
81
+ <button role="tab" aria-controls="setting">setting.scss</button>
82
+ </div>
83
+ <doc-code id="scss" data-type="scss" role="tabpanel">
84
+ /// Create some outline variations
85
+ ///
86
+ /// @require {variable} $outline-variations - Map variable
87
+ /// @param {string} $name - Name of the component
88
+ /// @param {array} $states - List of interactions
89
+ /// @param {string} $color - The initial color of the item (used for color, border and :hover background)
90
+ /// @param {string} $contrast - The initial contrast color of the item (:hover color)
91
+ /// @access public
92
+ ///
93
+
94
+ @include with-outline-variations($name, $states: (), $color: var(--#{$name}-background, var(--color-font)), $contrast: var(--#{$name}-color, var(--color-body)))
95
+ </doc-code>
96
+ <doc-code id="setting" data-type="scss" role="tabpanel">
97
+ $outline-variations: (
98
+ my-component-name
99
+ );
100
+ </doc-code>
101
+ </div>
102
+
103
+ <blockquote class="warning">
104
+ <p>To use this mixin you must have added the name of your item inside the variable <code>$outline-variations</code> into the file <code>.../variables/_setting</code>.</p>
105
+ </blockquote>
106
+
107
+ <h2>Set color variation</h2>
108
+
109
+ <p>This mixin will create the <code>.COLOR</code> classes to transform an item to multiple color variations.</p>
110
+
111
+ <div class="code-group">
112
+ <div role="tablist">
113
+ <button role="tab" aria-controls="scss">SCSS</button>
114
+ <button role="tab" aria-controls="setting">setting.scss</button>
115
+ </div>
116
+ <doc-code id="scss" data-type="scss" role="tabpanel">
117
+ /// Create some color variations
118
+ ///
119
+ /// @require {variable} color-variations - Map variable
120
+ /// @param {string} $name - Name of the component
121
+ /// @param {boolean} @param {array} $states - List of interactions
122
+ /// @access public
123
+ ///
124
+
125
+ @include with-color-variations($name, $states: ())
126
+ </doc-code>
127
+ <doc-code id="setting" data-type="scss" role="tabpanel">
128
+ $color-variations: (
129
+ my-component-name: (primary, other-color)
130
+ );
131
+ </doc-code>
132
+ </div>
133
+
134
+ <blockquote class="warning">
135
+ <p>To use this mixin you must have added the name of your item and the colors inside the variable <code>$color-variations</code> into the file <code>.../variables/_setting</code>.</p>
136
+ </blockquote>
137
+
138
+ <h2>Transform table to be responsive</h2>
139
+
140
+ <p>This mixin will transform a <code>&lt;table&gt;</code> to a more responsive view. You must use this mixin inside a <code>@media</code> or a <code>@container</code>.</p>
141
+
142
+ <p>It also required to add the attribute <code>data-label="Name of the column"</code> on each <code>&lt;td&gt;</code>.</p>
143
+
144
+ <div class="code-group">
145
+ <div role="tablist">
146
+ <button role="tab" aria-controls="html">HTML</button>
147
+ <button role="tab" aria-controls="scss">SCSS</button>
148
+ <button role="tab" aria-controls="css">CSS</button>
149
+ </div>
150
+ <doc-code id="html" data-type="html" role="tabpanel">
151
+ <table>
152
+ <thead>
153
+ <tr>
154
+ <th>Header A</th>
155
+ <th>Header B</th>
156
+ <th>Header C</th>
157
+ </tr>
158
+ </thead>
159
+ <tbody>
160
+ <tr>
161
+ <td data-label="Header A">Cell</td>
162
+ <td data-label="Header B">Cell</td>
163
+ <td data-label="Header C">Cell</td>
164
+ </tr>
165
+ </tbody>
166
+ </table>
167
+ </doc-code>
168
+ <doc-code id="scss" data-type="scss" role="tabpanel">
169
+ @container (max-width:800px) {
170
+ table {
171
+ @include as-responsive-table()
172
+ }
173
+ }
174
+ </doc-code>
175
+ <doc-code id="css" data-type="css" role="tabpanel">
176
+ --table-grid-template: 15ch 1fr;
177
+ </doc-code>
178
+ </div>
179
+
180
+ <blockquote>
181
+ <p>By default the grid is set on 2 columns (15 characters and auto).</p>
182
+ </blockquote>
183
+
184
+ <h2>Flex grid utilities</h2>
185
+
186
+ <p>There two mixins to make it easier to change the offset and the width of a specific column when used with the <b>grid</b> component.</p>
187
+
188
+ <div class="code-group">
189
+ <div role="tablist">
190
+ <button role="tab" aria-controls="html">HTML</button>
191
+ <button role="tab" aria-controls="scss">SCSS</button>
192
+ </div>
193
+ <doc-code id="html" data-type="html" role="tabpanel">
194
+ <div class="flex-grid">
195
+ <div>Flex 1</div>
196
+ <div>Flex 2</div>
197
+ <div>Flex 3</div>
198
+ <div id="wider">Wider of 3</div>
199
+ <div id="offset">Offset of 2</div>
200
+ </div>
201
+ </doc-code>
202
+ <doc-code id="scss" data-type="scss" role="tabpanel">
203
+ #wider {
204
+ @include flex-grid-wider-column(3)
205
+ }
206
+
207
+ #offset {
208
+ @include flex-grid-offset-column(2)
209
+ }
210
+ </doc-code>
211
+ </div>
212
+
213
+ <blockquote class="warning">
214
+ <p>This mixins only work with <code>.flex-grid</code></p>
215
+ </blockquote>
216
+
217
+ <blockquote>
218
+ <p>By default the <code>flex-grid-wider-column</code> parameter is <code>2</code>, to have the width equal of two columns width.</p>
219
+ </blockquote>
220
+ <blockquote>
221
+ <p>By default the <code>flex-grid-offset-column</code> parameter is <code>1</code> to take the place of one column width.</p>
222
+ </blockquote>
223
+
224
+ </doc-layout>
225
+ <script type="module" src="/main.js"></script>
226
+ </body>
227
+
228
+ </html>
@@ -0,0 +1,15 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Documentations: Javascript ></title>
8
+ </head>
9
+
10
+ <body data-preload>
11
+ <doc-layout></doc-layout>
12
+ <script type="module" src="/main.js"></script>
13
+ </body>
14
+
15
+ </html>
@@ -0,0 +1,98 @@
1
+ /**
2
+ * ------------------------------------------------------------------
3
+ * Demo
4
+ * ------------------------------------------------------------------
5
+ * This is the code for the demonstration code
6
+ *
7
+ * @author Natacha Herth
8
+ * @version 0.0.1
9
+ * @copyright Natacha Herth, design & web development
10
+ *
11
+ */
12
+
13
+ import Dialog from './../../../js/_dialog.js'
14
+ const dialogs = document.querySelectorAll('.demo-dialog')
15
+ if (dialogs) dialogs.forEach(dialog => new Dialog(dialog))
16
+
17
+ const demoDialogFormJS = document.getElementById('demoDialogFormJs')
18
+ if (demoDialogFormJS) {
19
+ demoDialogFormJS.addEventListener('dialog:submited', (e) => {
20
+ const value = e.detail.form.querySelector('input').value
21
+ document.getElementById('favorite').innerText = value
22
+ })
23
+ }
24
+
25
+ import Dropdown from "./../../../js/_dropdown.js"
26
+ const dropdowns = document.querySelectorAll('.demo-dropdown')
27
+ if (dropdowns) dropdowns.forEach(dropdown => new Dropdown(dropdown))
28
+
29
+ import Slider from './../../../js/_slider.js'
30
+ const sliders = document.querySelectorAll('.demo-slider')
31
+ if (sliders) sliders.forEach(slider => new Slider(slider))
32
+
33
+ const sliderFade = document.getElementById('sliderFade')
34
+ if (sliderFade) {
35
+ const mySliderObj = new Slider(sliderFade, {
36
+ behavior: 'instant',
37
+ autoplay: 4000
38
+ })
39
+ sliderFade.addEventListener('slider:changing', (ev) => {
40
+ const src = mySliderObj._slides[ev.detail.current].querySelector('img').getAttribute('src')
41
+ sliderFade.style.backgroundImage = `url("${src}")`
42
+ })
43
+ }
44
+
45
+ import Autofill from "./../../../js/_autofill"
46
+ const autofills = document.querySelectorAll('.demo-autofill')
47
+ if (autofills) autofills.forEach(autofill => new Autofill(autofill))
48
+
49
+ import CheckAll from "./../../../js/_check-all"
50
+ const checkboxAll = document.getElementById('demoCheckboxAll')
51
+ if (checkboxAll) new CheckAll(checkboxAll)
52
+
53
+ import Comfort from "./../../../js/_comfort"
54
+ new Comfort('demo-confort')
55
+
56
+ import Consent from "./../../../js/_consent"
57
+ if (document.getElementById('demoCookies')) {
58
+ new Consent('demo-consent', 'demoCookies', 'demoCookiesPreferences')
59
+ }
60
+
61
+ import FormHelper from "./../../../js/utilities/_form-helper"
62
+ const passwordButton = document.getElementById('demoPassword')
63
+ if (passwordButton) passwordButton.addEventListener('click', () => FormHelper.togglePassword(passwordButton))
64
+ const demoToggleFormButton = document.getElementById('demoToggleFormButton')
65
+ const demoToggleFormContent = document.getElementById('demoToggleFormContent')
66
+
67
+ if (demoToggleFormButton && demoToggleFormContent) {
68
+ const fields = demoToggleFormContent.querySelectorAll('input,select,textarea')
69
+ new Toggle(demoToggleFormButton)
70
+ demoToggleFormButton.addEventListener('toggle:changed', (e) => {
71
+ FormHelper.toggleAttributes(fields, !demoToggleFormContent.hidden, {
72
+ reset: true,
73
+ disabled: true,
74
+ required: ['test'],
75
+ unchanged: ['test']
76
+ })
77
+ })
78
+ }
79
+
80
+ import Scroll from "./../../../js/_scroll"
81
+ const scrollSpy = document.getElementById('demoScrollSpy')
82
+ if (scrollSpy) {
83
+ new Scroll(scrollSpy, {
84
+ navigation: 'demoScrollNav'
85
+ })
86
+ }
87
+
88
+ import Sortable from "./../../../js/_sortable"
89
+ const sortables = document.querySelectorAll('.demo-sortable')
90
+ if (sortables) sortables.forEach(sortable => new Sortable(sortable))
91
+
92
+ import Toggle from "./../../../js/_toggle.js"
93
+ const toggles = document.querySelectorAll('.demo-toggle')
94
+ if (toggles) toggles.forEach(toggle => new Toggle(toggle))
95
+
96
+ import Tree from "./../../../js/_tree"
97
+ const trees = document.querySelectorAll('.demo-tree')
98
+ if (trees) trees.forEach(tree => new Tree(tree))
@@ -0,0 +1,102 @@
1
+ const template = document.createElement('template')
2
+ template.innerHTML = `
3
+ <style>
4
+ pre {
5
+ white-space: preserve;
6
+ word-spacing: normal;
7
+ word-break: normal;
8
+ word-wrap:normal;
9
+ tab-size:0;
10
+ hyphen:none;
11
+ margin: 0;
12
+ }
13
+ .copy-btn {
14
+ all: unset;
15
+ color: white;
16
+ position: absolute;
17
+ top: 0;
18
+ right: 0;
19
+ padding:.75rem;
20
+ font-size:12px;
21
+ line-height:12px;
22
+ border-radius: .5rem;
23
+ opacity: .5;
24
+ transition: opacity .25s ;
25
+ }
26
+ .copy-btn:hover {
27
+ cursor:pointer;
28
+ opacity: 1;
29
+
30
+ }
31
+ pre {
32
+ overflow: auto;
33
+ }
34
+ </style>
35
+ <button class="copy-btn" aria-label="Copy to clipboard" title="Copy to clipboard">
36
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16">
37
+ <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z"/>
38
+ <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z"/>
39
+ </svg>
40
+ </button>
41
+ <div class="my-code"></div>
42
+ `
43
+
44
+ import { getHighlighter } from 'shiki'
45
+ const highlighter = await getHighlighter({
46
+ themes: ['one-light', 'one-dark-pro'],
47
+ langs: ['javascript', 'html', 'css', 'scss', 'sh'],
48
+ })
49
+
50
+ class DocCode extends HTMLElement {
51
+ constructor() {
52
+
53
+ super()
54
+
55
+ // Define the shadow
56
+ const shadow = this.attachShadow({ mode: 'open' })
57
+ shadow.append(template.content.cloneNode(true))
58
+ this.code = shadow.querySelector('.my-code')
59
+
60
+ // Get the type of code
61
+ const type = this.getAttribute('data-type') ?? 'html'
62
+
63
+ // Clean the code
64
+ let content = type === 'html' ? this.innerHTML : this.textContent
65
+ var pattern = content.match(/\s*\n[\t\s]*/)
66
+ content = content.replace(new RegExp(pattern, "g"), '\n').replaceAll('=""', '')
67
+ content = content.trim()
68
+
69
+ // Run the shiki plugin
70
+ const shiki = highlighter.codeToHtml(content, {
71
+ lang: type,
72
+ theme: 'one-dark-pro'
73
+ })
74
+
75
+ // Replace the content by the shiki <pre>
76
+ this.code.innerHTML = shiki
77
+
78
+ // Init copy button
79
+ const delay = (s) => new Promise((resolve) => setTimeout(resolve, s * 1000))
80
+ const copyBtn = shadow.querySelector('.copy-btn')
81
+ if (copyBtn) copyBtn.addEventListener('click', async () => {
82
+ navigator.clipboard.writeText(content)
83
+ copyBtn.innerHTML = `
84
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard-check" viewBox="0 0 16 16">
85
+ <path fill-rule="evenodd" d="M10.854 7.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7.5 9.793l2.646-2.647a.5.5 0 0 1 .708 0"/>
86
+ <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z"/>
87
+ <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z"/>
88
+ </svg>
89
+ `
90
+ await delay(2)
91
+ copyBtn.innerHTML = `
92
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-clipboard" viewBox="0 0 16 16">
93
+ <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z"/>
94
+ <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z"/>
95
+ </svg>
96
+ `
97
+ })
98
+ }
99
+ }
100
+
101
+ customElements.define('doc-code', DocCode)
102
+
@@ -0,0 +1,14 @@
1
+ const template = document.createElement('template')
2
+ template.innerHTML = `
3
+ <div><slot></slot></div>
4
+ `
5
+
6
+ class DocDemo extends HTMLElement {
7
+ constructor() {
8
+ super()
9
+ const shadow = this.attachShadow({ mode: 'open' })
10
+ shadow.append(template.content.cloneNode(true))
11
+ }
12
+ }
13
+
14
+ customElements.define('doc-demo', DocDemo)