Skip to content

Commit

Permalink
Merge pull request #152 from perfect-things/v9
Browse files Browse the repository at this point in the history
add utilities docs - part 1
  • Loading branch information
tborychowski authored Sep 9, 2023
2 parents ecca0df + 1c5db20 commit 606fa97
Show file tree
Hide file tree
Showing 56 changed files with 1,125 additions and 142 deletions.
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@ Changelog
=========


## v9.0.0 *(2023-08-28)*
- **Improved**: `Tooltip` was simplified and now the positioning ensures that the tooltip is always visible on the screen.
- **Improved**: `Popover` will now update its position when the window is resized.
## v9.0.0 *(2023-08-?)*
- **New**: added `Utils` page in the docs with APIs to the utility functions exposed by the library.
- `Tooltip` was simplified and now the positioning ensures that the tooltip is always visible on the screen.
- `Popover` will now update its position when the window is resized.
- The tip of the `Tooltip` and `Popover` will now try to be centered on the target element (if the box was offset from the screen edge).
- Improved keyboard focus for notifications: when a notification is dismissed from the keyboard (Escape) the focus will be moved to the next available notification.
- Improved & standardised z-index throughout the components.
- Tweaked `Menu` positioning to update on window resize.
- Tweaked `MenuItem` for responsiveness (e.g. add ellipsis if the text is too long).



### Breaking changes
- The `events` property was dropped from the `Tooltip`, leaving *hover* and *focus* events as the default. For use cases when the *click* was needed, `Popover` should be used instead.
Expand Down
4 changes: 2 additions & 2 deletions docs-src/api-table/ApiTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ function buildType (prop) {
if (!prop.type) prop.type = '-';
const types = (Array.isArray(prop.type) ? prop.type : [prop.type]).map(t => `<i>${t}</i>`);
res.push(types.join(' | '));
if (prop.required) res.push('<em>required</em>');
if (prop.default) res.push(`<br>(defaults to ${prop.default})`);
if (typeof prop.required !== 'undefined') res.push('<em>required</em>');
if (typeof prop.default !== 'undefined') res.push(`<br>(defaults to ${prop.default})`);
return res.join(' ');
}
</script>
4 changes: 3 additions & 1 deletion docs-src/code-example/CodeExample.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{#if !notitle}
<hr><h3>Example</h3>
{#if nohr === undefined}<hr>{/if}
<h3>Example</h3>
{/if}
<pre><code class="language-svelte">
{@html encode(html)}
Expand All @@ -8,6 +9,7 @@
<script>
export let html = '';
export let notitle = false;
export let nohr = undefined;
function encode (s) {
return s
Expand Down
1 change: 1 addition & 0 deletions docs-src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ export { Tree } from './tree';

export { Menu } from './menu';
export { Icon } from './icon';
export { Utils } from './utils';
export { Splitter } from './splitter';
export { ColorPalette } from './color-palette';
47 changes: 47 additions & 0 deletions docs-src/components/utils/Utils.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.section-utils {
--nav-sidebar-width: 240px;
}
.section-utils .dark-mode-switch { right: calc(var(--nav-sidebar-width) + 20px); }

.utilities { padding-bottom: 3rem; margin-right: var(--nav-sidebar-width); }


.utilities h3.util {
scroll-margin-top: 4.2rem;
font-size: 1.1rem;
color: var(--ui-color-accent);
font-family: Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;
}


.utilities-nav {
position: fixed;
right: 0;
top: 0;
bottom: 0;
z-index: 52;
margin: 0;
padding: 1rem 2rem;
overflow-y: auto;
width: var(--nav-sidebar-width);
border-left: 1px solid var(--ui-color-border-2);
background-color: var(--ui-color-background-input);
}

.section-utils .btn-scroll-top { right: calc(var(--nav-sidebar-width) + 20px); }


@media (1px <= width <= 900px) {
.section-utils .dark-mode-switch { right: 0.6rem; }
.section-utils .btn-scroll-top { right: 1rem; }
.utilities { margin-right: 0; }
.utilities-nav {
position: static;
border-left: none;
width: auto;
z-index: initial;
margin-top: 2rem;
background-color: unset;
}

}
48 changes: 48 additions & 0 deletions docs-src/components/utils/Utils.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<div class="sticky-block utilities utilities-nav">
<h3>Utility properties</h3>
<ul>
{#each props as item}
<li><a href="#Utils/{item}">{item}</a>
{/each}
</ul>

<h3>Utility Functions</h3>
<ul>
{#each fns as item}
<li><a href="#Utils/{item}">{item}</a>
{/each}
</ul>
</div>

<div class="sticky-block utilities" id="top">
<h2>Utility properties</h2>
{#each props as item}
<div class="utility">
<svelte:component this="{Properties[item]}" /><br>
</div>
{/each}
<p>
<em>*</em> <a href="https://svelte.dev/docs/svelte-components#script-4-prefix-stores-with-$-to-access-their-values">
svelte store variables</a> - when reading the value, add <em>$</em> to the name, e.g.
<em>$FOCUSABLE_SELECTOR</em>.
</p>
</div>

<div class="sticky-block utilities">
<h2>Utility Functions</h2>
{#each fns as item}
<div class="utility">
<svelte:component this="{Functions[item]}" /><br>
</div>
{/each}
</div>



<script>
import * as Functions from './functions';
import * as Properties from './properties';
const props = Object.keys(Properties);
const fns = Object.keys(Functions);
</script>
48 changes: 48 additions & 0 deletions docs-src/components/utils/functions/align-item.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<h3 class="util" id="AlignItem">alignItem(config)</h3>
<p>Aligns an element to another element,
ensuring that the aligned element remains within the viewport.
</p>
<ul>
<li><em>config</em> - an object with the configuration (see below).
<li>Returns <em>position</em> - whether the aligned item is above (top) or below (bottom) the target.
</ul>

<API props="{apiProps}" title="Config object schema"/>

<CodeExample nohr html="{example}" />


<script>
import { API } from '../../../api-table';
import { CodeExample } from '../../../code-example';
const apiProps = [
{ name: 'element', type: 'HTMLElement', description: 'main element that will be aligned.' },
{ name: 'target', type: 'HTMLElement', description: 'target element to align to.' },
{ name: 'alignH', type: ['left', 'right', 'center'], default: 'left', description: 'Horizontal position' },
{ name: 'offsetH', type: 'number', default: 0, description: 'horizontal offset of the aligned position (in pixels).' },
{ name: 'alignV', type: ['top', 'bottom'], default: 'bottom', description: 'Vertical position' },
{ name: 'offsetV', type: 'number', default: 2, description: 'vertical offset of the aligned position (in pixels).' },
{ name: 'viewportPadding', type: 'number', default: 10, description: 'padding from the viewport (in pixels).' },
{ name: 'setMinWidthToTarget', type: 'boolean', default: false, description: 'whether to set the minWidth of the element to the width of the target.' },
];
const example = `
<script>
const button = document.querySelector('.button1');
const popup = document.querySelector('.popup1');
const pos = alignItem({
element: popup,
target: button,
alignH: 'left',
alignV: 'bottom',
});
// it may happen that there is not enough space to align the popup as requested
// in this case, the popup will be aligned to the opposite side
console.log('position:', pos); // 'top'
&lt;/script>
`;
</script>
32 changes: 32 additions & 0 deletions docs-src/components/utils/functions/animate.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<h3 class="util" id="Animate">animate(element, from, to, options?)</h3>

<p>Animates an element from one state to another. Shortcut & wrapper for the native javascript animation.</p>

<API props="{apiProps}" title="Parameters"/>
<p>Returns a promise which resolves when the animation finishes.</p>


<CodeExample nohr html="{example}" />


<script>
import { API } from '../../../api-table';
import { CodeExample } from '../../../code-example';
const apiProps = [
{ name: 'element', type: 'HTMLElement', description: 'An element that will be animated.' },
{ name: 'from', type: 'object', description: 'object of properties to animate from, e.g. <em>&lbrace; opacity: 0 &rbrace;</em>' },
{ name: 'to', type: 'object', description: 'object of properties to animate to, e.g. <em>&lbrace; opacity: 1 &rbrace;</em>' },
{ name: 'options', type: 'object', description: 'optional object of animation options: duration, easing, fill (see more at <a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/KeyframeEffect#options">MDN</a>).' },
];
const example = `
<script>
const el = document.querySelector('.some-div');
animate(el, { opacity: 0 }, { opacity: 1 }, { duration: 1000 })
.then(() => console.log('animation finished'));
&lt;/script>
`;
</script>
22 changes: 22 additions & 0 deletions docs-src/components/utils/functions/blink.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<h3 class="util" id="Blink">blink(element, duration = 160)</h3>
<p>Animates an element by changing its opacity from 0.5 to 1.</p>
<ul>
<li><em>element</em> - HTMLElement to animate
<li><em>duration</em> - how long to animate (in ms).
<li>Returns a promise which resolves when the animation finishes.
</ul>
<CodeExample nohr html="{example}" />


<script>
import { CodeExample } from '../../../code-example';
const example = `
<script>
const el = document.querySelector('.some-div');
blink(el).then(() => console.log('animation finished'));
&lt;/script>
`;
</script>
31 changes: 31 additions & 0 deletions docs-src/components/utils/functions/debounce.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<h3 class="util" id="Debounce">debounce(fn, timeout = 300)</h3>
<p>The "debounced" function will only be called after it has not been called for <em>timeout</em> milliseconds.</p>
<ul>
<li><em>fn</em> - function to debounce.
<li><em>timeout</em> - milliseconds to wait before calling <em>fn</em>.
</ul>

<p>
This is a useful e.g. when attaching an event listener to an event that is fired repeatedly & quickly (like scroll or resize).<br>
Attaching a heavy function to such an event can cause performance issues, so debouncing it will ensure
that the function is only called after it has not been called for <em>timeout</em> milliseconds.
</p>

<CodeExample nohr html="{example}" />


<script>
import { CodeExample } from '../../../code-example';
const example = `
<script>
function original() {
console.log('resizing has stopped for 300ms');
}
const debounced = debounce(original);
window.addEventListener('resize', debounced);
&lt;/script>
`;
</script>
20 changes: 20 additions & 0 deletions docs-src/components/utils/functions/deep-copy.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<h3 class="util" id="DeepCopy">deepCopy(object)</h3>
<p>This is just an alias for an oddly-named native function: <b>structuredClone</b>.</p>
<ul>
<li><em>object</em> - any object or array to clone.
</ul>
<CodeExample nohr html="{example}" />


<script>
import { CodeExample } from '../../../code-example';
const example = `
<script>
const original = {a: 1, b: 2, c: 3};
const clone = deepCopy(original);
&lt;/script>
`;
</script>
39 changes: 39 additions & 0 deletions docs-src/components/utils/functions/empty.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<h3 class="util" id="Empty">empty(value)</h3>
<p>Similar to PHP's <em>empty</em> - returns true if a value is empty.</p>
<ul>
<li><em>value</em> - any data type.
</ul>

<p>Empty will return true if the <em>value</em> is one of the following:</p>
<ul>
<li><em>undefined</em>
<li><em>null</em>
<li><em>empty string</em>
<li><em>empty array</em>
<li><em>empty object</em>
</ul>

<CodeExample nohr html="{example}" />


<script>
import { CodeExample } from '../../../code-example';
const example = `
<script>
empty(); // true
empty(null); // true
empty(''); // true
empty([]); // true
empty({}); // true
empty(0); // false
empty(false); // false
empty('0'); // false
empty([0]); // false
empty({a: 0}); // false
&lt;/script>
`;
</script>
16 changes: 16 additions & 0 deletions docs-src/components/utils/functions/format-date.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<h3 class="util" id="FormatDate">formatDate(date)</h3>
<p>Converts date to a string in the format: <em>YYYY-MM-DD HH:mm</em>.</p>

<CodeExample nohr html="{example}" />


<script>
import { CodeExample } from '../../../code-example';
const example = `
<script>
formatDate(new Date()); // 2020-01-01 12:00
&lt;/script>
`;
</script>
26 changes: 26 additions & 0 deletions docs-src/components/utils/functions/fuzzy.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<h3 class="util" id="Fuzzy">fuzzy(haystack = '', needle = '')</h3>
<p>Fuzzy finds if <em>haystack</em> contains characters from the <em>needle</em> in the same order.</p>
<ul>
<li><em>haystack</em> - a string to be searched in.
<li><em>needle</em> - a string to search for.
</ul>

<p>It's useful for filtering lists of items by a search string.</p>

<CodeExample nohr html="{example}" />


<script>
import { CodeExample } from '../../../code-example';
const example = `
<script>
fuzzy('hello world', 'hell'); // true
fuzzy('hello world', 'helloo'); // true
fuzzy('hello world', 'helll'); // true
fuzzy('hello world', 'hellooo'); // false
&lt;/script>
`;
</script>
Loading

0 comments on commit 606fa97

Please sign in to comment.